TypeScript 笔记
TypeScript 笔记
WaterBoat[[toc]]
代码库
环境搭建
1 | 安装 |
体验一下 ts
类型注解(annotation)
- 我们告诉 typescript 变量是什么类型
1 | let a: number; // annotation |
- 声明数字
1 | let a: number = 10; |
- 声明数组
1 | let a: number[] = [1, 2, 3]; // 声明数字数组 |
- 声明对象
1 | const obj: { name: string; age: number } = { name: "李四", age: 19 }; |
- 函数
1 | function fn(): void { |
- 结构赋值
1 | function sum({ a, b }: { a: number; b: number }): number { |
- 任意类型
1 | let num: any = "1"; |
- 声明数组对象
1 | interface Obj { |
类型推断(inference)
- typescript 会自动的判断变量的类型
1 | let a = 123; // 鼠标放上 a 去看 |
never 类型的理解
- 一个无法执行完成的函数的返回值可以是 never
1 | function fn(): never { |
必看(运行环境)
使用的编辑器 vscode
typescript 版本 4.2.4
tsconfig.json 配置
:::tip
笔记的全部代码都是开启严格模式,没开严格模式的地方会特别说明
:::
1 | { |
基础
数据类型
any
类型除了不能赋值给never
与其他所有类型兼容unknow
可以被其他所有类型赋值除
any
和unknow
外,void
不可赋值给其他类型
:::tip
strict 严格模式在 tsc -init 之后的 tsconfig.json 里面设置
:::
不开启
strict选项时,
void可被
null、
undefined、
never`赋值开启
strict
选项时,void
可被undefined
和never
赋值
定义变量
JavaScript 的类型分为两种:原始数据类型(Primitive data types)和对象类型(Object types)。
原始数据类型包括:布尔值、数值、字符串、null
、undefined
以及 ES6 中的新类型 Symbol
和 BigInt
。
null 和 undefined 是所有类型的子类型 也就是说 undefined
类型的变量,可以赋值给 number
类型的变量 (在没有开启严格模式的情况下)
1 | // 冒号后面的玩意叫类型注解 |
定义函数
JavaScript 没有空值(Void)的概念,在 TypeScript 中,可以用 void
表示没有任何返回值的函数:
1 | function fn(): void { |
声明一个 void 的变量只能被赋值成 null 和 undefined (在没有开启严格模式的情况下 null 才能 赋值给 void 变量)
1 | let v: void = null; // "strict": false |
:::tip
在 TypeScript 的类型定义中,=>
用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
:::
1 | let returnStr: (str: string) => string = function (str) { |
重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理
类似于 java 里面的方法重载
例如我们定义一个函数名为 add 的函数,当传入的值是 number 类型的时候我们就相加,传入的是 string 类型的时候我们就转换成数字再相加
1 | function add(x1: number, x2: number): number; |
定义任意值 any
任意值(Any)用来表示允许赋值为任意类型。
简单理解如果你把一个变量注解成了 any 那么你写的 ts 代码就变成了 js 了
1 | let a: any = "123"; |
等价于
1 | var a = "123"; |
类型推论 Type Inference
如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。
也就是说编译器会帮你推断一个类型
1 | let num = 1; // 鼠标移动到 num 上会看到 vscode 给你推断出了number |
以上代码等价于
1 | let num: number = 1; |
TypeScript 会在没有明确的指定类型的时候推测出一个类型,这就是类型推论
::: warning
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any
类型而完全不被类型检查
:::
联合类型 Union Types
联合类型(Union Types)表示取值可以为多种类型中的一种。
联合类型使用 |
分隔每个类型。
案例
1 | // hello 变量既可以是 number 类型也可以是 string 类型 |
访问联合类型的属性或方法
:::warning
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
:::
1 | // 访问联合类型的共有属性 |
对象的类型——接口 Interface
什么是接口
在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
案例
1 | // 接口名称一般大写 |
以上的案例我们发现接口定义之后用里面定义的 name 和 age 在 obj 里面都得完完整整的写完 那么我不想写完呢?或者只写一个呢?
可选属性
有时我们希望不要完全匹配一个形状,那么可以用可选属性
1 | interface Person { |
那么我想让这个 interface 里面的属性可以任意添加呢?
任意属性
有时候我们希望一个接口允许有任意的属性,可以使用如下方式
1 | interface Person { |
::: warning
需要注意的是,一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
:::
1 | interface Person { |
那么我想让 interface 里面的属性一开始就被赋值并且只能被读取不能被修改呢?
只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly
定义只读属性
1 | interface Person { |
类型断言 Type Assertion
语法
1 | // 值 as 类型 或 <类型>值 一般用前者 |
类型断言的用途
简单理解就是,现在你比编译器更懂现在的这个变量是什么类型
1 | function getValue(value: number | string): void { |
确定赋值断言
用处告诉 Ts 该属性被明确的赋值
1 | let x: number; |
进阶
类型别名 type
类型别名用来给一个类型起个新名字
1 | type Obj = { |
:::tip
类型别名常用于联合类型
:::
元组 Tuple
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
元组定义成啥样就要验证遵守定义的规则
1 | let arr1: [number, string] = [1, "hello"]; |
枚举 Enum
枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。
1 | enum Days { |
枚举成员会被赋值为从 0
开始递增的数字,同时也会对枚举值到枚举名进行反向映射:
1 | enum Days { |
枚举可以手动赋值
1 | enum Day { |
泛型 Generics
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
例子
1 | // 创建一个函数,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值: |
:::tip
思考 : 返回的是一个任意类型的数组,若是我后面直接调用 result[0].toFixed(2) 字符串上明明没有这个方法我强行调用不就报错了? 还有一个问题,我们输入 result[0]. 点时候在 vscode 中的代码提示没有了.我们写 ts 可以说就是为了良好的代码提示这时提示没有了是否意味着我们写错了?
此时我们需要一个工具我们给 value 输入什么类型 createArray 函数就返回什么类型的数组,并且 result 会被类型推断为正确的类型
此时泛型就可以登场了
:::
1 | // 创建一个函数,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值: |
泛型约束
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法
1 | // 用泛型创建一个函数返回传入字符串的 length |
此时我们就需要告诉编译器 str 上肯定存在 length 属性,我们就需要使用到泛型约束
1 | // 用泛型创建一个函数返回传入字符串的 length |
泛型接口
1 | // 泛型接口 |
我们可以把泛型参数提前到接口名上
1 | // 泛型接口 |
一些总结
高级类型
交叉类型,使用类型操作符
&
联合类型,使用类型操作符
|
索引类型,使用类型操作符
keyof
,T[K]
映射类型,使用类型操作符
in
条件类型,使用类型操作符
T extends U ? X : Y
infer
另外还有用于类型保护的类型谓词中的
is
操作符以及上面所介绍的typeof