目录
1. 类型注解
2. 常用基础类型
1.JavaScript 已有类型
2. TypeScript 新增类型
3. 原始类型
4. 数组类型
1.类型[]写法, 如
2.Array<类型>写法, 如
5. 联合类型
6. 类型别名
7. 函数类型
void 类型
函数可选参数
8. 对象类型
使用类型别名
带有参数的方法的类型
箭头函数形式的方法类型
对象可选属性
9. 接口 interface
接口和自定义类型的区别
接口继承
10. 元组
11. 类型推论
12. 字面量类型
使用场景和模式
13. 枚举
数字枚举
字符串枚举
枚举实现原理
14. any 类型
15. 类型断言
16. typeof
TypeScript 是 JS 的超集,TS 提供了 JS 的所有功能,并且额外的增加了:类型系统
JS 有类型(比如,number/string 等),但是 JS 不会检查变量的类型是否发生变化,而 TS 会检查
TypeScript 类型系统的主要优势:可以显示标记出代码中的意外行为,从而降低了发生错误的可能性
示例代码
let age: number = 18;
说明:代码中
:number
就是类型注解
类型注解约束了只能给该变量赋值该类型的值
错误演示
// 错误原因:将 string 类型的值赋值给了 number 类型的变量,类型不一致
let age: number = '18';
可以将 TS 中的常用基础类型分为两类
number/string/boolean/null/undefined/symbol
object
(数组、对象、函数等)注意:原始类型在 TS 和 JS 中写法一致, 对象类型在 TS 中更加细化,每个具体对象都有自己的类型语法
number/string/boolean/null/undefined/symbol
特点:可完全按照 JavaScript 中的名称来书写
let age: number = 18;
let username: string = '张三';
let isMerry: boolean = false;
let unique: Symbol = Symbol('shuiruohanyu');
数组两种写法
类型[]
写法, 如let userList: string[] = ['John', 'Bob', 'Tony'];
let peopleList: object[] = [{ name: '张三', age: 18 }];
let user2List: Array = ['John', 'Bob', 'Tony'];
let people2List: Array
数组中既有 number 类型,又有 string 类型,这个数组的类型应该如何写?
可以用|
(竖线)分割多个类型, 如
let str: string | number = 1;
str = '张三';
如果数组中可以是字符串或者数字,则可以这么写
let arr: Array = [1, 2, '张三'];
当一个复杂类型或者联合类型过多或者被频繁使用时,可以通过类型别名来简化该类型的使用
用法:type
名称 = 具体类型
type CustomArray = Array;
let arr1: CustomArray = [1, 2, '张三'];
以上代码中,type
作为创建自定义类型的关键字
除了变量,我们常见的类型指定还有针对函数的类型声明
函数类型需要指的是 函数参数
和返回值
的类型,这里分为两种写法
// 单独指定函数返回值和函数参数
function add(num1: number, num2: number): number {
return num1 + num2;
}
// 指定变量形式的
const add2 = (num1: number, num2: number): number => {
return num1 + num2;
};
// 同时指定参数和返回值
type CustomFunc = (num1: number, num2: number) => number;
const add3: CustomFunc = (num1, num2) => {
return num1 + num2;
};
注意: 当函数作为表达式时,可以通过类似箭头函数形式的语法来为函数添加类型,这种形式只适用于函数表达式
当我们的函数定义为没有返回值的类型时,可用关键字void
表示
// 没有返回值的函数
type CustomFunc1 = (num1: string, num2: number) => void;
const combinStr: CustomFunc1 = () => {};
如果一个函数没有返回值,此时,在 TS 的类型中,应该使用 void
类型
const add4 = () => {};
// 如果什么都不写 表示add4函数的类型为void
const add5 = (): void => {};
// 这种写法明确指定返回值为void与上方的类型相同
const add6 = (): undefined => {
return undefined;
};
// 如果指定返回值为undefined return undefined
当我们定义函数时,有的参数可传可不传,这种情况下,可以使用 TS 的可选参数来指定类型
比如,在使用数组的slice
方法时,我们可以直接使用slice()
也可以传入参数 slice(1)
也可以slice(1,3)
const slice = (start?: number, end?: number): void => {};
?
表示该参数或者变量可传可不传
注意:可选参数只能出现在参数列表的最后, 即必须参数必须在可选参数之前
JS 中的对象是由属性和方法组成的,TS 的对象类型是对象中属性和方法的描述
写法
// 如果有多个属性 可以换行 去掉间隔符号
let person3: {
name: string;
sayHello: Function;
} = {
name: '王五',
sayHello() {},
};
总结: 可是使用{ }
来描述对象结构
属性采用属性名:类型
形式
函数可以采用 方法名(): 返回值类型
或者 函数名: Function
(不指定返回值)的形式
直接使用{ }
会降低代码可读性,不具有辨识度,更推荐使用类型别名添加对象类型
type PersonObj = {
name: string;
sayHello(): string;
};
const p1: PersonObj = {
name: '高大大',
sayHello() {
return this.name;
},
};
如果对象中的函数带有参数,可以在函数中指定参数类型
// 带参数的函数方法
type PersonObj2 = {
name: string;
sayHello(start: number): string;
};
const p2: PersonObj2 = {
name: '高大大',
sayHello(start) {
return this.name;
},
};
// 箭头函数形式定义类型
type People = {
sayHello: (start: number) => string;
};
const p3: People = {
sayHello() {
return '';
},
};
对象中的若干属性,有时也是可选的,此时我们依然可以使用?
来表示
type Config = {
method?: string;
url: string;
};
const func = (config: Config) => {};
func({ url: '/a' });
当一个对象类型被多次使用时,一般使用接口(interface)描述对象的类型,达到复用的目的
interface
关键字来声明接口I
为开头接口后不需要分号
// 接口
interface IPeople {
name: string;
age: number;
sayHello(): void;
}
let p: IPeople = {
name: '老高',
age: 18,
sayHello() {},
};
相同点:都可以给对象指定类型
不同点: 接口只能为对象指定类型, 类型别名可以为任意类型指定别名
比如,这两个接口都有 x、y 两个属性,重复写两次,可以,但很繁琐
interface Point2D {
x: number;
y: number;
}
interface Point3D {
x: number;
y: number;
z: number;
}
interface Point2D { x: number; y: number }
interface Point3D extends {
z: number
}
我们使用extends
关键字实现了 Point3D 继承了 Point2D 的所有属性的定义, 同时拥有继承的属性和自身自定义的属性
当我们想定义一个数组中具体索引位置的类型时,可以使用元祖。
原有的数组模式只能宽泛的定义数组中的普遍类型,无法精确到位置
元组是另一种类型的数组,它确切知道包含多少个元素,以及特定索引对应的类型
let position: [number, number] = [39.5427, 116.2317];
在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型
也就是说,由于类型推论的存在,在某些地址类型注解可以省略不写。
// 变量creater_name自动被推断为 string
let creater_name = 'gaoly';
// 函数返回值的类型被自动推断为 number
function addCount(num1: number, num2: number) {
return num1 + num2;
}
推荐:能省略类型注解的地方就省略(偷懒,充分利用 TS 类型推论的能力,提升开发效率)
技巧:如果不知道类型,可以通过鼠标放在变量名称上,利用 VSCode 的提示来查看类型
下面的代码类型分别是什么?
// 字面量类型
let str1 = '张三';
const str2 = '张三';
通过 TS 的类型推导可以得到答案
1.变量 str1 的变量类型为: string
2.变量 str2 的变量类型为 '张三'
解释:str1 是一个变量(let),它的值可以是任意字符串,所以类型为:string
str2 是一个常量(const),它的值不能变化只能是 '张三',所以,它的类型为:'张三'
此时,‘张三’就是一个字面量类型,即某个特殊的字符串也可以作为 TS 中的类型
任意的 JS 字面量(对象,数组,数字)都可以作为类型使用
type Direction = 'left' | 'right' | 'up' | 'down';
// 使用自定义类型:
function changeDirection(direction: Direction) {
console.log(direction);
}
// 调用函数时,会有类型提示:
changeDirection('up');
// 枚举
// 创建枚举
enum Direction2 {
Up,
Down,
Left,
Right,
}
// 使用枚举类型
function changeDirection2(direction: Direction2) {
console.log(direction);
}
// 调用函数时,需要应该传入:枚举 Direction 成员的任意一个
// 类似于 JS 中的对象,直接通过 点(.)语法 访问枚举的成员
changeDirection2(Direction2.Up);
数字枚举
// Down -> 11、Left -> 12、Right -> 13
enum Direction {
Up = 10,
Down,
Left,
Right,
}
enum Direction {
Up = 2,
Down = 4,
Left = 8,
Right = 16,
}
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT'
}
// 会被编译为以下 JS 代码:
var Direction;
(function (Direction) {
Direction['Up'] = 'UP'
Direction['Down'] = 'DOWN'
Direction['Left'] = 'LEFT'
Direction['Right'] = 'RIGHT'
})(Direction || Direction = {})
let obj: any = { x: 0 };
obj.bar = 100;
obj();
const n: number = obj;
在项目开发中,尽量少用 any 类型
有时候你会比 TS 更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型。 比如,
const aLink = document.getElementById('link');
const aLink = document.getElementById('link') as HTMLAnchorElement;
解释:
as
关键字实现类型断言另一种语法,使用 <>
语法,这种语法形式不常用知道即可:
// 该语法,知道即可:在react的jsx中使用会报错
const aLink = document.getElementById('link');
技巧:在浏览器控制台,通过 __proto__
获取 DOM 元素的类型
console.log(typeof 'Hello world'); // ?
let p = { x: 1, y: 2 };
function formatPoint(point: { x: number; y: number }) {}
formatPoint(p);
function formatPoint(point: typeof p) {}
typeof
操作符来获取变量 p 的类型,结果与第一种(对象字面量形式的类型)相同