Typescript学习笔记,从入门到精通,持续记录
- Typescript
- 2022-10-08
- 1139热度
- 0评论
安装Typescript
1.安装
基础入门
Typescript可以理解为带静态类型的Javascript;
1.原始数据类型
- 布尔值,boolean
- 数值,number
- 字符串,string
- 空值,void 表示没有任何返回值的函数
- Null 和 Undefined
如果定义的时候有赋值,类型就会被推断为这个值得类型;
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查
2.任意值(any)
如果是一个普通类型,在赋值过程中改变类型是不被允许的:
但如果是 any 类型,则允许被赋值为任意类型。
3.联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种,联合类型使用 | 分隔每个类型。
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法
4.对象的类型—接口
在 TypeScript 中,我们使用接口(Interfaces)来定义对象的类型。在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
定义的变量比接口少、多一些属性是不允许的,赋值的时候,变量的形状必须和接口的形状保持一致。
4.1 可选属性
可选属性的含义是该属性可以不存在,但是仍然不允许添加未定义的属性。
4.2 任意属性
有时候我们希望一个接口允许有任意的属性,可以使用如下方式:
使用 [propName: string]
定义了任意属性取 string
类型的值。
4.3 只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用 readonly 定义只读属性
只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
5.数组的类型
6.函数的类型
在 JavaScript 中,有两种常见的定义函数的方式——函数声明(Function Declaration)和函数表达式(Function Expression):
一个函数有输入和输出,要在 TypeScript 中对其进行约束,需要把输入和输出都考虑到,其中函数声明的类型定义较简单:
函数表达式定义如下:
我们也可以使用接口的方式来定义一个函数需要符合的形状:
6.1 可选参数
与接口中的可选属性类似,我们用 ? 表示可选的参数:
6.2 参数默认值
在 ES6 中,我们允许给函数的参数添加默认值,TypeScript 会将添加了默认值的参数识别为可选参数,此时就不受「可选参数必须接在必需参数后面」的限制了:
6.3 剩余参数
ES6 中,可以使用 ...rest 的方式获取函数中的剩余参数(rest 参数):
事实上,items 是一个数组。所以我们可以用数组的类型来定义它:
注意,rest 参数只能是最后一个参数,关于 rest 参数,可以参考 ES6 中的 rest 参数。
6.4 重载
重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。
7.类型断言
类型断言(Type Assertion)可以用来手动指定一个值的类型。
需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误:
8.声明文件
参考:http://ts.xcatliu.com/basics/declaration-files.html
进阶
1.类型别名
2.字符串字面量类型
3.元组
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
4.枚举
枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。
枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射
编译后:
5.类与接口
实现(implements)是面向对象中的一个重要概念。一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性。
6.泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
定义泛型的时候,可以一次定义多个类型参数:
7.声明合并
如果定义了两个相同名字的函数、接口或类,那么它们会合并成一个类型:
内置对象
Typescript内置了所有js、dom对象,核心库类型定义文件:https://github.com/Microsoft/TypeScript/tree/main/src/lib
命名空间
使用 namespace 关键字定义命名空间,可以在命名空间内部定义变量、函数表达式、函数声明、接口和 类等值。
为了让命名空间外部可以访问命名空间内部声明的值和类型,使用 export 关键字导出指定的值和类型;
引用外部文件的命名空间内的成员时,需要export指定命名空间
相关总结
- 类型库:https://github.com/DefinitelyTyped/DefinitelyTyped/
- TypeScript 核心库的定义文件中定义了所有浏览器环境需要用到的类型,并且是预置在 TypeScript 中的。
- Node.js 不是内置对象的一部分,如果想用 TypeScript 写 Node.js,则需要引入第三方声明文件:npm install @types/node --save-dev
- 类型别名用来给一个类型起个新名字。type Name = string;
- 字符串字面量类型,type EventNames = 'click' | 'scroll' | 'mousemove'; 使用EventNames 就等于之后的三个类型;
- 数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。let tom: [string, number] = ['Tom', 25];
- 枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等,也可以给枚举项手动赋值:。
- 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
- 代码检查:http://ts.xcatliu.com/engineering/lint.html
- 编译选项:http://ts.xcatliu.com/engineering/compiler-options.html
Es6 类
1.属性和方法
2.类的继承
使用 extends 关键字实现继承,子类中使用 super 关键字来调用父类的构造函数和方法
3.存取器
使用 getter 和 setter 可以改变属性的赋值和读取行为:
4.静态方法
使用 static 修饰符修饰的方法称为静态方法,它们不需要实例化,而是直接通过类来调用:
Es7 类
Es7相关提案在Typescript中已实现。
1.实例属性
ES6 中实例的属性只能通过构造函数中的 this.xxx 来定义,ES7 提案中可以直接在类里面定义:
2.静态属性
ES7 提案中,可以使用 static 定义一个静态属性:
TypeScript 中类的用法
TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。
- public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
- private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
- protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
1.抽象类
abstract 用于定义抽象类和其中的抽象方法
tsconfig.json
如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。
声明文件
1.相关语法
ts中的相关语法:
- declare var 声明全局变量
- declare function 声明全局方法
- declare class 声明全局类
- declare enum 声明全局枚举类型
- declare namespace 声明(含有子属性的)全局对象
- interface 和 type 声明全局类型
- export 导出变量
- export namespace 导出(含有子属性的)对象
- export default ES6 默认导出
- export = commonjs 导出模块
- export as namespace UMD 库声明全局变量
- declare global 扩展全局变量
- declare module 扩展模块
- /// 三斜线指令
declare module 'cos':
如果你使用了一个 JavaScript 库(如 cos),但该库没有提供 .d.ts 类型定义文件,你可以通过 declare module 手动声明该模块的类型。这可以让 TypeScript 编译器理解模块的结构,从而提供类型检查和智能提示。
如果 cos 已经有类型定义,但你希望为其添加新的类型扩展,也可以使用 declare module。
2.三斜线指令
三斜线指令也是 ts 在早期版本中为了描述模块之间的依赖关系而创造的语法。随着 ES6 的广泛应用,现在已经不建议再使用 ts 中的三斜线指令来声明模块之间的依赖关系了。
类似于声明文件中的 import,它可以用来导入另一个声明文件。与 import 的区别是,当且仅当在以下几个场景下,我们才需要使用三斜线指令替代 import:
- 当我们在书写一个全局变量的声明文件时,在全局变量的声明文件中,是不允许出现 import, export 关键字的。一旦出现了,那么他就会被视为一个 npm 包或 UMD 库,就不再是全局变量的声明文件了。故当我们在书写一个全局变量的声明文件时,如果需要引用另一个库的类型,那么就必须用三斜线指令
- 当我们需要依赖一个全局变量的声明文件时,当我们需要依赖一个全局变量的声明文件时,由于全局变量不支持通过 import 导入,当也就必须使用三斜线指令来引入
- 拆分声明文件,当我们的全局变量的声明文件太大时,可以通过拆分为多个文件,然后在一个入口文件中将它们一一引入,来提高代码的可维护性。
3.d.ts文件
ts 会解析项目中所有的 *.ts 文件、 .d.ts 结尾的文件。所以全局类型声明放在.d.ts中,可直接使用,不需要手动去引入。非全局则需要引入
问题总结
1.通过下标获取对象属性
ts直接通过属性名下标访问对象属性会报错,需要通过keyof处理。