116194308030846571
前言
TypeScript是由微软进行开发和维护的一种开源的编程语言。TypeScript是JavaScript的严格语法超集,提供了可选的静态类型检查。(维基百科)
TypeScript本质上是JavaScript的超集,所以JavaScript的所有用法都可以在TypeScript上直接使用,本文只介绍TypeScript的特殊用法
编译器
下载依赖
1
| npm install -g typescript
|
编译生成JS文件
-w:监视模式,每当源码发生改变就立即执行编译
编译指定文件
1
| tsc <file_1>.ts <file_2>.ts
|
根据配置文件编译指定文件
compilerOptions.outDir:指定输出目录
include:指定包含的文件或目录
exclude:指定排除的文件或目录
tsconfig.json1 2 3 4 5 6 7
| { "compilerOptions": { "outDir": "./", }, "include": ["./"], "exclude": ["./dist"] }
|
变量
声明变量
定义变量
- 自动类型推导,定义变量时的数据类型根据值的类型决定
常量
定义常量
基本数据类型
1 2 3 4 5 6 7 8 9
| const 变量名: number = 0;
const 变量名: string = "";
const 变量名: boolean = false;
const 变量名: null = null;
const 变量名: undefined = undefined;
|
进制表示
数组类型
定义数组元素的数据类型
1
| const 变量名: 数据类型[] = [值, 值];
|
元组类型
定义元祖元素的数据类型
1
| const 变量名: [数据类型, 数据类型] = [值, 值];
|
对象类型
定义空对象
定义对象属性的数据类型
1 2 3
| const 变量名: { 属性名: 数据类型 } = { 属性名: 值 }
|
1 2 3
| const 变量名: { 属性名 } = { 属性名: 值 }
|
1 2
| let a: { c: string, d: string } = { c: "", d: "" }; let b: { c: string } = a;
|
多个属性
1 2 3 4
| const 变量名: { 属性名1: 数据类型, 属性名2: 数据类型 } = { 属性名1: 值, 属性名2: 值 }
|
多行定义属性
1 2 3 4 5 6 7
| const 变量名: { 属性名1: 数据类型, 属性名2: 数据类型 } = { 属性名1: 值, 属性名2: 值 }
|
1 2 3 4 5 6 7
| const 变量名: { 属性名1: 数据类型 属性名2: 数据类型 } = { 属性名1: 值, 属性名2: 值 }
|
可选的属性
1 2 3
| const 变量名: { 属性名?: 数据类型 } = { 属性名: 值 }
|
- 可选的对象属性的数据类型实质上是这个数据类型与
undefined类型的联合类型(数据类型 | undefined)
1 2 3
| const 变量名: { 属性名?: 数据类型 | undefined } = { 属性名: 值 }
|
只读的属性
1 2 3 4 5
| const 变量名: { readonly 属性名: 数据类型 } = { 属性名: 值 }
|
函数作为对象属性
传送门
函数类型
定义函数
通过函数声明定义函数
通过函数表达式定义函数
- 通过函数表达式定义函数时,需要在类型中定义函数类型表达式
1
| const 函数名: () => void = function() {};
|
1
| const 函数名 = function() {};
|
定义形参的数据类型
1
| function 函数名(形参名: 数据类型) {}
|
多个形参
1
| function 函数名(形参名: 数据类型, 形参名: 数据类型) {}
|
不定长形参
1
| function 函数名(...形参名: 数据类型[]) {}
|
可选的形参
1
| function 函数名(形参名?: 数据类型) {}
|
- 可选的函数形参的数据类型实质上是这个数据类型与
undefined类型的联合类型(数据类型 | undefined)
1
| function 函数名(形参名: 数据类型 | undefined) {}
|
1
| function 函数名(形参名1: 数据类型, 形参名2?: 数据类型) {}
|
形参的默认值
1
| function 函数名(形参名: 数据类型 = 默认值) {}
|
1
| function 函数名(形参名 = 默认值) {}
|
- 有默认值的形参可以不传递实参,也可以接收
unedfined值作为实参,最终实参的值都是默认值
1 2 3 4 5 6
| function fn(k = "default") { console.log(k); }
fn(); fn(undefined);
|
函数作为实参
- 函数作为其他函数的实参时,这个函数的形参最好直接数据类型推导,因为在其他函数已经定义了这个函数的形参类型
1 2 3
| function 函数名(f: (形参名: 数据类型) => void) {}
函数名(function (形参名) {});
|
- 函数作为其他函数的实参时,这个函数的形参个数无需匹配
1 2 3
| function 函数名(f: (形参名1: 数据类型, 形参名2: 数据类型) => void) {}
函数名(function (形参名1) {});
|
定义返回值的数据类型
1 2 3
| function 函数名(): 数据类型 { return 返回值; }
|
空类型
- 如果如果函数的返回值类型为
void,返回值也可以是undefined
1 2 3
| function 函数名(): void { return undefined; }
|
- 如果函数的返回值类型
void是由上下文推导而得来的,那么不强制要求_不返回任何数据或返回undefined,否则必须_不返回任何数据或返回undefined
永无类型
never类型可以用于描述一个函数永远不会成功得到返回值,比如:死循环、抛出异常
1 2 3
| function 函数名(): never { while (true); }
|
1 2 3
| function 函数名(): never { throw new Error(); }
|
never类型也可以用于描述不应当被赋值为这个类型的变量,如果被赋值为这个类型的变量,则会编译期报错
1 2 3 4 5
| function 函数名(形参名: 数据类型) { if (typeof 形参名 === "string") { const 变量名: never = 形参名; } }
|
函数调用签名
- 如果一个对象的属性是函数类型,可以通过_函数调用签名_的方式定义数据类型
声明
1 2 3 4
| interface 接口名 { 属性名: 属性数据类型 (形参名: 形参数据类型): 返回值类型 }
|
定义
1 2 3 4
| const 变量名: 接口名 = function(形参名: 形参数据类型): 返回值类型 { return 返回值; } 变量名.属性名 = 属性值;
|
调用
1 2
| console.log(变量名(实参值)); console.log(变量名.属性名);
|
构造函数调用签名
- 如果一个对象的属性是构造函数类型,可以通过_构造函数调用签名_的方式定义数据类型
声明
1 2 3 4
| interface 接口名 { 属性名: 属性数据类型 new (形参名: 形参数据类型): 返回值类型 }
|
定义
1 2 3 4
| const 变量名: 接口名 = function(形参名: 形参数据类型): 对象类型 { return 对象; } as unknown as 接口名; 变量名.属性名 = 属性值;
|
调用
1 2
| console.log(new 变量名(实参值)); console.log(变量名.属性名);
|
函数的重载
- 编写重载签名
- 编写通用的实现
1 2 3 4 5
| function fn(arg: string) function fn(arg: number) function fn(arg: any) { console.log(arg); }
|
字面量类型
任意类型
any类型的变量可以赋值给非any类型的变量,所以会污染原本有数据类型的变量,这个变量的数据类型最终会根据传递的数据重新自动推导
1 2 3 4 5
| let a: any = ""; let b: number;
b = a; console.log(typeof b);
|
1 2 3
| let a: any = "";
console.log(a.length);
|
未知类型
unknow类型的变量不可以赋值给非unknow类型的变量,所以不会污染原本有数据类型的变量
1 2 3 4 5 6
| let a: unknown; let b: number; let c: unknown;
c = a;
|
unknown类型的变量不可以直接操作任意属性和方法,但是可以通过数据类型转换,从而调用属性和方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| let a: unknown = ""; let b: string;
if (typeof a === "string") { b = a; console.log(b.length); }
b = a as string; console.log(b.length);
b = <string>a; console.log(b.length);
|
联合类型
交叉类型
- 必须满足两种数据类型才可以匹配成功
- 如果是非类或接口之间的交叉类型,那么实际为
never类型
- 如果是类或接口之间的交叉类型,那么必须满足两者定义的所有属性才可以匹配成功
类型别名
声明类型别名
使用类型别名
类型守卫
typeof操作符
1 2 3 4 5 6
| let a: string | null; let b: string;
if (typeof a === "string") { b = a; }
|
instanceof操作符
1 2 3 4 5 6
| let a: Date | null; let b: Date;
if (a instanceof Date) { b = a; }
|
in操作符
1 2 3 4 5 6
| let a: { key1: string } | { key2: number }; let b: string;
if ("key1" in a) { b = a.key; }
|
类型断言
1 2 3 4
| let a: unknown = ""; let b: string;
b = a as string;
|
1 2 3 4
| let a: unknown = ""; let b: string;
b = <string>a;
|
非空类型断言
1 2 3 4
| let a: string | null; let b: string;
b = a!;
|
常量类型断言
1 2 3 4
| let a = { key: "value" } as const; let b: "value";
b = a.key;
|
接口
声明接口
1 2 3
| interface 接口名 { 属性名: 数据类型 }
|
可选的属性
1 2 3
| interface 接口名 { 属性名?: 数据类型 }
|
使用接口
通过交叉类型使用多个接口
通过同名接口补充接口定义的属性
1 2 3 4 5 6 7
| interface 接口名 { 属性名1: 数据类型 }
interface 接口名 { 属性名2: 数据类型 }
|
继承
1 2 3 4 5 6 7
| interface Father { 属性名1: 数据类型 }
interface Son extends Father { 属性名2: 数据类型 }
|
类
声明类
实现接口
1 2 3
| class 类名 implements 接口名 { 属性名: 数据类型 }
|
完成