TypeScript语言

324 阅读15分钟

一、TypeScript 概述

TypeScript 是一门基于 JavaScript 之上的编程语言,它重点解决了 JavaScript语言自有类型系统的问题;通过使用TypeScript的语言可以大大提高代码的可靠程度;

二、类型系统

解决JavaScript类型系统之前,先来解释两组在区分不同编程语言时提到的名词:

  • 强类型和弱类型,它是从 类型安全 维度区分不同编程语言
  • 静态类型和动态类型, 它是 类型检查 唯独区分不同编程语言
1、类型安全

类型安全 的角度来说,编程语言分为了 强类型弱类型

  • 强类型的定义:从 语言层面 限制 函数实参类型 必须与 形参类型 完全相同 image.png
  • 弱类型的定义: 从 语言层面 不会限制实参的类型 image.png
  • 由于这种强弱类型之分 根本 不是某一个权威就够的定义;有更好的鉴定方式:
    • 强类型有 更强类型约束,而 弱类型中 几乎没有约束
    • 换句话说:强类型语言中 不允许任意 的 隐式类型转换;弱类型语言中则 允许任意 的数据隐式类型转换
  • 变量类型允许随时改变的特点,不是强弱类型的差异;
1、类型检查

类型检查 的角度分为:静态类型语言 与 动态类型语言

  • 静态类型语言的特点:一个变量声明时,它的类型就是 明确的;声明过后,它的类型就不允许再修改;
  • 动态类型语言的特点:在 运行阶段 才能 明确 变量类型,变了类型随时也可以发生变化;也可以这么说: 动态类型语言中的 变量没有类型的,而变量中存放的 值是有类型的
3. 所欲语言在类型系统的分类

image.png

三、JavaScript类型系统特征

由于JavaScript是一名 弱类型且动态类型的语言;语言的本身类型系统非常薄弱,可以说JavaScript根本没有一个类型系统;这个语言的特征用一个比较流行的词:人性;因为它几乎没有任何类型的限制,所有JavaScript这门语言也是及其灵活多变的;但是在灵活多变的表象后 缺失了类型系统的可靠性---不靠谱;

  • 为什么JavaScript不是强类型/静态类型的语言呢?
    • 早前的JavaScript应用简单,早期的JavaScript的功能非常简单,早期规模较小
    • JavaScript是一门 脚本语言不需要编译,直接在运行环境运行;JavaScript没有编译环节,设计成静态类型也是没有意义的;因为静态类型语言需要在编译阶段 进行类型检查;
    • 大规模应用下,这种【优势】变成了短板

四、弱类型的问题

  • Javascript的弱类型语言中,必须要等到运行阶段,才能发现在代码当中的类型异常,而且不是立即去执行这个foo方法,而且在某一个特定时间去执行,例如我们把它放到一个 setTimeout 当中,直到这个setTimeout执行了,才会执行。 强类型语言在这里调用对象当中不存在的成员,在语法层面就会报错;
 const obj ={}
 obj.foo()
 // 对象中明显不存在该方法,但是在语言语法层面是可以这么写的,只是把代码放在浏览器环境去运行的时候,会报错:obj.foo is not function;
  • 类型不确定,造成函数功能发生改变;
function sum(a, b) {
    return a +b
}
console.log(100, 100) // ok 
console.log(100, '100') //传入字符串,函数是字符串连接过后的结果;
// sum就是去计算这两个数的和,我们玩的是两数的话,结果自然是正常的,但是如果我们候传入的是字符串,

// 那这种情况下,我们这个函数的作用就完全发生了变化,那他会返回我们对两个字符串连接过后的结果,那这就是因为类型不确定所造成的一个最典型的问题呢,

//有人说我们可以通过自己的约定去规避这个问题,的确通过约定方式是可以规避这个问题,

//但是你要知道约定是根本没有任何保障的,特别是在多人集中开放情况下,我们根本没办法保证每个人都能遵循所有原因,而我们用强类型语言的话,那这种情况就会彻底避免掉,

//因为在强类型语言当中,如果我们要求传入的数字,那你传入的是其他类型的值,在语法上就行不通。
  • 对象索引器的一种错误的用法
const obj ={}
obj[true] = 100
console.log(obj['true'])
//创建一个对象,通过索引器的语法给对象添加属性,由于JavaScript是弱类型的,所以我们可以在索引当中使用任意类型的值作为属性,而在它的内容会自动转换成字符串;
// 比如我们这个obj去添加true作为属性,那最终的对象,他实际的属性就是字符串的true

总结: 弱类型语言它的 弊端 是使得明显的,只是在代码量小的情况下,这些问题我们可以通过 约定方式去规避,而对于一些开发周期特别长的大规模项目那这种。君子约定的方式仍然会存在隐患,那只有在 语法层面的强制要求才能够提供更可靠的保障,所以说呢,强类型语言的代码,在代码可靠程度上是有明显优势的,那使用强类型语言呢,就可以提前消灭一大部分有可能会存在的类型异常,而不必等到我们在运行过程中再去慢慢的一半。

五、强类型的优势

    1. 错误更早暴露: 在编码阶段消除大部分的类型问题,不用等运行阶段暴露错误
    1. 代码更智能,编码更准确
    • 弱类型其实编写JavaScript的智能提示是不起作用的,这是因为开发工具没有办法推断出该成员的类型问题;
    • 强类型语言编辑器时时刻刻知道每个变量的类型,智能提升能够有效的提高编码编码效率以及编码的准确性;
    1. 重构更牢靠: 重构是指对代码有一种破坏性的改动,例如:删除对象成员,修改对象成员名称
    • 弱类型: 假如修改对象成员的一个方法,但是这个方法在其他方法中有引用,修改之后不会有提示,只有在运行阶段才会发现;但是强类型会及提出来
    1. 减少不必要的类型判断
 function() {
     // 强类型不需要这种判断
     if(typeof a !== 'number' || typeof b !=== 'numver') {
         throw new TypeError('参数必须时数字')
     }
     return a + b
 }

六、Flow的概述

Flow是JavaScript的静态类型检查器,它是2014年由Facebook推出一款功能,使用它可以补充JavaScript的弱类型所带来的弊端,为 JavaScript提供更完善的类型系统,目前在react、vue都可以看到Flow的使用;

工作原理: 让我们在代码当中通过添加类型注解的方式,来标记代码当中的变量、参数是什么类型,然后Flow根据这些注解来检查这些代码当中存在类型使用的异常,从而实现在开发阶段对类型异常的检查,这就避免了在运行阶段再返现类型使用的错误;

举例:

现有一个sum()函数:
function sum(a, b) {
    return a + b
}
经过Flow的标记:
// a: number, b: number 叫 类型注解`,变量名: 类型
function sum(a: number, b: number) { // 表示ab必须接受一个number的数值
    return a + b
}
sum(100, 500) // ok
sum(100, '20') // error

对于代码的当中的额外的类型注解,我们可以在运行之前通过Babel或者Flow官方的一个模块自动去除,所以在生产环境当中,这些类型注解不会有任何的影响,而且Flow并 不要求给每个变量添加注解;

Flow 只是一个小工具,使用起来特性简单

1、快速上手,使用Flow

    1. 生产一个packpackage.json: npm init -y
    1. npm install -g yarn
    1. npm install flow-bin // 安装
    1. 文件添加标记 @flow
    1. yarn flow init //初始化
    1. yarn flow 运行文件
//@flow  
//注释添加 @flow,方法中添加参数类型
function sum( a: number, b: number) {
    return a +b
}
sum(100, 100)

2、编译移除类型注解

代码没有办法使用node命令执行文件,如果执行就报错,解决方法:移除注解;

  • 移除类型注解方案一:添加flow-remove-types模块:

    • 安装 yarn add flow-remove-types --dev
    • 执行 yarn flow-remove-types . -d dist(yarn flow-remove-types src/ -d dist) // .表示当前目录,dist表示去除注释以后的js文件的输出路径;
  • 移除类型注解方案一: 添加编译工具Babel + preset-flow

    • yarn add @babel/core @babel/cli @babel/preset-flow --dev
    • .babelrc
          {
              "presets": ["@babel/preset-flow"]
          }
      
    • yarn babel src -d dist

3、开发工具插件

vscode插件:

更直观体现代码类型异常问题: flow language support; 注意这里要注意保存之后才会观看类型异常;

其他开发工具请查看flow官方文档

4、Flow 类型推断

根据代码当中的使用情况,去推断出来变量的类型特征就是类型推断, 建议代码当中添加类型注解,让代码有更多的可读性 ;例如以下代码:

- flow 仍然会发现类型上使用的错误,它会根据我们调用时传入的字符串推断出来n参数是字符串类型,字符串类型是不能进行乘法运算; 觉大多数情况下,建议代码当中添加类型注解,让代码有更多的可读性

 function square(n){//这里没有添加类型注解;
  return n*n
 }
 square(2)

5、Flow 类型注解

添加类型注解 更明确的限制类型,而且后期去理解这里代码也是更有帮助,尽量可能去使用类型注解;

  • 类型注解可以 标记 变量, 函数参数, 返回值类型 image.png
//标记函数参数:
function square(a: number) {return n*n}
let num: number = 100  // 标记变量
function foo() :number{} //  标记返回值类型
function foo() :void{} // 返回值类型没有的话,添加void

6、Flow 原始类型

在用法上,使用flow命令,根据代码当中添加的类型注解去检查代码使用类型异常;

Flow支持哪些类型以及更高级的用法

  • 原始数据类型
const a: string = 'foobar'
const b: number = NaN // NaN , Infinity
const c: boolean = false; // true
const d: nll = null
const e: void = undefined  // 存储undefined 标记为void
const f: symbol = Symbol()

7、Flow 数组类型

数组类型需要 泛型参数 用来表述 数组当中每个元素的类型

const arr1: Array<number> = [1,2,3] // 泛型: Array<>
const arr2: number[] = [1,2,3] //全部有数字组成的数组
// 固定长度的数组,叫做元组, foo有两个类型string、number,那么这里存储两个元素的数组,一个是string, 一个number
const foo: [string, number] = ['foo', 100]  

8、Flow 对象类型

const obj1: {foo: string, bar: number}  = { foo: 'string', bar: 100}// 当前变量中必须具有foo, bar两个成员而去它们的类型是string, number

// 成员后添加 ?:表示该成员可有可无
const obj2: {foo?: stringbar: number} = {bar: 100}

// 当作键值对集合使用
const obj3 ={}
obj3.key1 = 'value1'
obj3.key2 = 100
// 利用索引器的语法设置;指定类型后,只能是这种类型,可以添加该类型的任何值
const obj4 ={[string]: string } = {} // 不限制该对象的成员个数,但是限制该成员的成员类型
obj3.key1 = 'value1'
obj3.key2 = 100

9、Flow 函数类型

一般对函数参数、函数返回值的约束;

function foo(callback:(string,number)=>number){ 
// 限制回调函数的参数类型,返回值number
    callback('string',100) 
 } 
foo(function(str,n){ 
  //必須传递参数为strign和number的值 return n 
})

10、Flow 特殊类型

  • 字面量类型:
    • 限制变量必须是某一个值;
    • 配合联合类型用法;
    • 可以用在普通类型中
    • type关键词单独申明类型,申明一个类型,用来表示多个类型联合之后的结果
// 限制变量必须是某一个值;  a:类型是foo,此时a变量中存储foo的字符串,除此之外就会报错
const a: 'foo' = 'foo' 
// 配合联合类型用法
const type: 'success' | 'warning' | 'danger' = 'success'
// 可以用在普通变量中
const b: string |number = 'string' // 100 ,此时已string类型,也可以是number类型
// type关键词单独申明类型,申明一个类型,用来表示多个类型联合之后的结果
type StringOrNumber = string| number // 表示可以使用string,number
const b: StringOrNumber = 'string'
  • Maybe(?)有可能
const gender: number = null  // 此时不能为空
//如果需要可以为空的话;可以在number前面添加?
const gender: ?number = null //  表示可以接受null ,undefined
等价于
const gender: number | null | void = undefined

11、Flow Mixed & Any

  • Mixed/Any: 接受任意类型的值
  • 两者之间的差异: Any是弱类型,Mixed是强类型
function passMixed(value: mixed) {
    value.substr(1)
    value * value  // 语法层面会直接报错
}
passMixed('string')
passMixed(100)

function passAny(value: any) {
    value.substr(1)
    value * value  // 语法层面不会报错,执行环境会报错
}
passAny('string')
passAny(100)

12、Flow运行环境API

Flow文档: www.saltycrane.com/cheat-sheet…

JavaScript不是独立工作的,它必须运行在某个特定的环境的当中,那例如:浏览器环境、node环境;运行环境一定会提供API使用,浏览器环境有:DOM,BOM;

七、TypeScript

1、TypeScript概念

TypeScript是JavaScript之上的编程语言,是Javascript的超集或者扩展集;其实就是在JavaScript原有的基础上的扩展特性,多出来的是一套更强大的 类型系统,以及对 ECMAScript新特性的支持,那最终会被编译成 原始的Javascriptimage.png 也就说使用TypeScript过后,开发者在开发过程中可以直接使用Typescript的新特性,以及它有更强大的类型系统开发工作,在完成开发工作之后,再将代码直接编译成可以生产环境直接运行的JavaScript代码; 避免我们在开发过程出现的类型异常,提高编码效率,代码的可靠程度;

TypeScript最终编译成JavaScript,任何一种Javascript运行环境都支持;例如:传统浏览器、node环境;TypeScript完整的编程语言,它的功能更加强大,生态也更健全、更完善;特别是对开发工具这一块特别友好;

Angular/VueJs.3 也开始使用 TypeScrip 取替 Flow

Typescript是前端领域中的第二语言; 如果是小项目,需要灵活自由,就会选择JavaScript本身; 如果是长周期项目,选择使用Typescript;

Typescript 的缺点:

  • 缺点一: 语言本身多了很多概念,例如:接口,枚举、泛型等等,这些概念提高了学习成本; 好在 Typescript 属于[渐进式];
    • 渐进式含义: 即便我们什么特性都不知道,我们可以立马去按照JavaScript的标准语法编写TypeScript的代码, 可以完全当作JavaScript去使用,然后我们再学习过程中,了解一个特性就使用一个特性;
  • 缺点二: 项目初期,TypeScript会增加一些成本: 因为项目初期会编写很多的类型声明,比如: 对象、函数会有很多类型声明编写;如果是长期维护的大型项目,很多时候是一劳永逸;

2、TypeScript 快速上手

    1. yarn init -- yes // 初始化管理package.json 项目
    1. yarn add typescript --dev // 出现一个./bin/tsc文件
    1. yarn tsc 文件名 //运行文件 ,tsc编译ts文件,检测类型,移除注解,去检查TypeScript新特性
//可以完全安好 JavaScript 标准语法编写代码
const hello = (name: string) => {
    console.log( `Helo ${name}`)
}

hello(100)  // error

3、TypeScript 配置文件

    1. 创建 tscconfig.json 的文件, yarn tsc --init
    • target: 编译过后的JavaScript采用的标准
    • module:commomJs/requireJs 输出的代码采用的方式进行模块化
    • outDir: "dist"; 编译结果输出到的文件夹
    • rootDir: 'src'; 源代码(typescript)所在的文件夹
    • sourceMap: true; 开启源代码映射,然后我们再调试的时候只用sourceMap源文件调试typescript的代码,更方便
    • strict: true; 开启所有严格检查选项
    1. 运行tsc项目: yarn tsc

TypeScript 原始数据类型

// 原始数据类型
const a: string = 'foobar'

const b: number = 100
const c: boolean = true
const d: number = null  //在tsconfig.json文件中开启:strictNullChecks:false

const e: void = undefined

const f: null = null
const g: undefined = undefined
const h: symbol = Symbol()

4、TypeScript 标准库声明

Symbol是TypeScript的内置对象类型;

标准库就是内置对象所对应的声明, 使用内置对象就要引用相对应的标准库否则找不到对应的类型,就会报错;

5、TypeScript 中文错消息

TypeScript支持多语言的开发设置; 强制中文: yarn tsc -- locale zh-CN;

vscode的错误消息:打开配置选项-》typescript locale-> zh-CN

6、TypeScript 作用域问题

设置到不同文件中不同的特性,那这种情况下,不同文件中遇到相同名称的现象;

  • 解决方案:
    • 使用立即执行函数;
    • 使用模块化:export {},因为每个模块都有输入自己的作用域;
01.ts ----------------------------
const a: number = 100
// 这里就会出现同名,报错
02.ts ----------------------------
const a number = 123 ==》修改
// 使用立即执行函数
(function() {
const a number = 123
})()
// 使用模块化: export {};

7、TypeScript Object 类型

TypeScript 的Object 类型并不是单指普通对象类型,而是泛指所有的非原始类型: 对象、数组、函数

// 如果传入原始类型,即会报错
const foo: object =[]/ function() {}/{}
// 如果需要普通对象的类型,对象类型限制,赋值的对象结构要跟对象结构一致,否则会报错;
const obj: {obj: number} = {foo:123}

8、TypeScript 数组 类型

  • 第一种: 泛型Array<>
  • 第二种: 元素类型[]
   const arr1: Array<number> = [1,23,4]
   const arr2: number[] = [1,23,3]

9、TypeScript 元组 类型

特殊的数据的解构,其实就是明确数据数量的长度明确数据类型的

  • 访问元组中某一个元素:
    • 利用数组下标的方式:const name = tuple[0]
    • 利用解构的方式: const [name, age] = tuple
  • 一般用来在函数中返回多个返回值
const tuple: [number, string] = [18, 'ax']
// 访问元组中某一个元素
const name = tuple[0]
const [name, age] = tuple

9、TypeScript 枚举 类型

在应用开发过程中,经常会涉及到需要用 某几个数值代表某种状态

  • 枚举的特点
    • 可以给一组数值名字分别起上更好理解的名字
    • 一个枚举中只会存在固定的值,并不会出现超出范围的可能性
    • 枚举类型运行的时候会入侵代码最终编译为一个双向键值对对象
const enum PostStatus {
    Draft = 0,
    Unpublished =1,
    Published = 2
    // 如果没有没有= 赋值状态,引用枚举从第一个开始累加
    // 如是字符串枚举,需要手动赋值
}
constt post = {
 title: 'hello',
 content: 'TypeScript is a typed superset',
// status:2 // 数字对应的什么状态,经常混进来一些其他的值(除了2的数值)
 status: PostStatus.Draft
}

10、TypeScript 函数 类型

对函数的输入和输出进行限制

  • 函数表达有两种方式
    • 函数声明
    • 函数表达式
// 函数声明
function func1(a: number, b?: number, ...rest: number[]): string { // ...rest:number 接受多个参数
// b?: number ?: 代表可选参数
    return 'func1'
}
func1(100, 100)
// 函数表达式
const func2 = function (a: number, b?: number): string {
// 函数表达式最终放在变量中,接受的变量是有类型的,一般情况下是类型推断出来的类型,
// 如果把一个函数作为参数传递,必须对回调函数进行约束参数的类型,可以使用箭头函数的方式接受什么类型
    return 'func2'
}

11、TypeScript 任意 类型

由于Javascript自身是弱类型的关系,很多内置的API,本身支持接受任意的参数,而TypeScript又是给予JavaScript之上的;难免会在代码当中接受任意类型的数据

function stringify(vaue: any) {
    return JSON.stringify(value)
}
// any仍然属于动态类型,不会做类型检查;语法上都不会报错
let foo: any = 'string'
foo = 100
foo.bar()

12、TypeScript 隐式类型推断

在typescript中没有明确通过注解去标记变量类型,会根据变量使用情况推断出变量类型,叫做 隐式类型推断

let age = 18  // 推断为number类型
age = 'string' // 此时会报错,因为age=18已经推断它为number类型
// 声明一个变量没有赋值,那么它将为any类型,那么语言都不会报错;
let foo 
foo = 100
foo = 'string'

13、TypeScript 类型断言

在有些特殊的情况下,TypeScript是无法推断出变量具体类型,而我们作为开发者,是知道这个代码的情况;举例

  • 类型断言的方式:辅助代码成员的类型,类型断言并不是类型转换,类型转换是运行的观念,类型断言是编译的观念
    • 使用关键子as
    • 使用<>
// 假定这个nums,来自一个明确的接口
const nums = [100,112,113]
// 这里的返回值一定是一个数字。它们认为有可能找不到。typescript就会推断为number、undefined
const res = nums.find(i => i>0) 
// const square = res * res
//使用关键子as 
const num1 = res as number // 明确告诉typeScript是number
//使用<>,当我们在代码中使用了JSX,会JSX标签产生冲突 
const num2 = <number>res

13、TypeScript 接口

一种规范,一种契约,约定对象的解构,使用接口,必须遵循接口全部的约定。typescript最直观的一个体现,用来约定一个对象应该有哪些成员,成员的类型

//举例:定义printPost,接受文章对象参数,对接受对象有一定要求
// 定义接口 文章对象有哪些成员
interface Post {
    title: string
    content: string
    subtitile?: string //  为可选成员
    readonly summary: string //只读成员
}
function printPost(post: Post) {
   console.log(post.title)     
   console.log(post.content)     
}
printPost({title: 'hello', content: 'A JavaScript'})
// 

总结: 接口就是用来 约束对象的解构,一个对象实现一个接口,它就必须拥有它所约束的所有成员

  • 接口约定成员:
    • 选可成员:举例在上
    • 只读成员: 不能再次修改
  • 动态成员:
// 定义的时候不知道有哪些成员,不能指定,所以用[key]
interface Cache {
    [prop: string]: string
}
const cashe:Cache = {}
cache.foo = 'value'  // 可以任意添加成员,但是类型必须为string

13、TypeScript 类

作用: 描述一类具体事物的抽象特征,例如:手机

用来描述一类具体对象的抽象成员; ES6以前,都是通过 函数+ 原型模拟实现类,ES6开始就有了类Class。 而在 typescript 中增强了class的相关语法;

  • 在typescript中 类的属性必须要有一个初始值或者在构造函数中赋值,目的: 为属性添加类型标记;除此之外,按照ES6标准添加一些方法
  • 类 访问修饰符:
    • private 只能在内部访问
    • public 公共的
    • protected 受保护的,只允许子类访问的成员
    • readonly 只读,不能修改,只能构造函数初始化/ 类型声明的时候通过 = 的方式初始化 两者只需其一
class Person {
   // 声明属性
    public name: string  = 'init name'
    private age: number = 18
    // 
    protected readonly gender: boolean
    //在typescript中 类的属性必须要有一个初始值或者在构造函数中赋值,目的: 为class的属性添加标记
    constructor(name: sting, age: number) {
        this.name = name
        this.age = age
    }
    sayHi (msg: string) {
        console.log(`I am ${naem},${msg}`)
        console.log(this.age)
    }
}
//constructor 被设为private ,Student不能在外部被访问,只能在类内部创静态方法,
class Student extends Person() {
    private constructor(name: string, age: number) {
        super(name, age)
        console.log(this.gender)
    }
    static create(name: string, age: numer) {
        return new Student(name, age)
    }
}
const tom = new Person('tom', 18)
 console.log(tom.age) // 报错,因为定义访问修饰符为私有的
 
 
 const jack = Student.create('jack', 18) // ok
 const jack1 = new Student('jack', 18) // error constructor 被设为private 

14、TypeScript 类与接口

举例: 手机是一个类型,实例都是能够打电话、发短信的 ,手机的特征是够打电话、发短信,但是打电话的不仅仅是手机,比较常见的座机也是可以打电话,但是座机并不属于手机的一类,因为不能发短信,不能拿着到处跑;这种情况会现 类与类 的共同特征, 那对这些公共特征使用 接口抽象 ,可以理解我手机也可以打电话,座机也可以打电话, 因为他们实现了相同的协议,这种协议叫做接口 类: 描述一类具体事物的抽象特征 接口:公共的特征使用

  • 使用 implements 实现接口实现类,
  • 一个接口只约束一个能力
// 人和动物都会吃,会跑,它们都有一个能力,这个时候可以用一个接口定义这个能力
// 一个接口只约束一个能力
interface Eat() {
    eat(food: string): void
}
interface Run() {
    run(distance: number): void
}
// 人
class Person implements Eat,Run {
    eat(food: string): void{
        console.log(`优雅的进餐: ${food}`)
    }
    run(distance: string): void{
        console.log(`直立行走: ${distance}`)
    }
}
//  动物
class Animal implements Eat,Run {
    eat(food: string): void{
        console.log(`呼噜呼噜的吃: ${food}`)
    }
    run(distance: string): void{
        console.log(`爬行: ${distance}`)
    }
}

14、TypeScript 抽象类

约束子类当中 **必须** 要有某一个成员,但是不同于接口, 抽象类 可以包含具体的实现方法,,而接口只包含成员的抽象,不包含具体的实现

  • 抽象方法也不需要方法体
  • 父类定义为abstract, 子类必须实现抽象方法体
  • 使用子类创建的对象时,就会同时拥有父类的方法,也拥有自身的方法

一般大类目: 使用抽象类,比如: 动物类;只是个泛指,不够具体,它下面有一个具体的分类

抽象类: 关键子 abstract,在类名前添加

//  abstract 抽象类, Animal被定义为抽象类,只能被继承,不能使用new的方式实例化
abstract class Animal {
   eat(food: string): void{
        console.log(`呼噜呼噜的吃: ${food}`)
    }
    //抽象方法也不需要方法体
    abstract run(distance: string): void
}
// 
class Dog extends Animal{
    run(distance: string): void{
        console.log(`爬行: ${distance}`)
    }
}
const d = new Dog()
d.eat('芒果')
d.run(100)

14、TypeScript 泛型 <T>

我们定义函数和接口和类的时候,没有定义具体的类型,等到使用的时候指定具体类型;(泛型就是声明这个函数的时候,不指定类型,等到调用时传递具体类型,作用就是极大程度的复用代码) 以函数为例:

  • 泛型: 使用<T>
  • 把我们定义时不能明确的类型,变成一个参数,让我们在使用的时候再去传递类型参数
// 只能接受一个number类型;
fucntion createNumberArray(length: number, value: number): number[] {
// 由于Array创建的是any类型的数组,指定元素的类型,指定方式通过泛型参数传递类型
  const arr = Array<number>(legnth).fill(value)
  return arr
}
const res = createNumberArray(3,100)
// res => [100,100,100]

// 使用泛型<T>,把类型变成一个参数
fucntion createNumberArray<T>(length: number, value: T): T[] {
    const arr = Array<T>(legnth).fill(value)
  return arr
}

- 把我们定义时不能明确的类型,变成一个参数,让我们在使用的时候再去传递类型参数
const res = createNumberArray<string>('3','100')

14、TypeScript 类型声明

在实际开发中,我们经过使用第三方模块, nmp模块并不一定使用typescript的编写,所以它所提供的模块不会有强类型的体验;

总结: TypeScript当中引用第三方模块,如果这个模块当中不包含所对应的类型声明文件,那么我门尝试安装所对应的声明模块;一般这个声明模块: @types/模块名, 那如果也没有对应的声明模块名,那只能使用 declare语句去声明所对应的类型

// 使用lodash 
// 在我们导入就开始报错了,找不到类型声明的文件。解决方法: 安装类型声明模块
// 类型声明模块: 只是对一个模块的类型声明,.d.t后缀名,专门解决声明模块
import { camelCase } from 'lodash' 
// 当我门直接调用的时候,并没有发现类型提示,需要单独进行类型申明, 原因是考虑普通的JS模块;
// 单独进行类型申明 declare,
declare fucntion camelCase(input: string): string
const res = camelCase(‘hello typed’)