声明:类型 = 类型对应变量
- let flag:boolean = true
- let age: number = 21;
- let name: string = "shixin";
- 复制代码
类型收敛——字面量类型
- const flag: true = true;
- const age: 21 = 21;
- const name: 'shixin' = 'shixin';
- 复制代码
在 TypeScript 中,null 与 undefined 类型都是有具体意义的类型。所以在默认情况下会被视作其他类型的子类型。
- const data1: null = null;
- const data2: undefined = undefined;
- const data3: number = null; // That's OK
- const data4: string = null; // That's OK
- 复制代码
tsconfig 配置项,会严格校验undefined和null。在该配置开启的环境下。undefined和null将不为其他类型的子类型
- {
- "extends": "./tsconfig",
- "compilerOptions": {
- "strictNullChecks": true
- }
- }
- 复制代码
- const data5: string = null; // error
- 复制代码
联合类型就是一个数组的可用的集合
- let numOrStr :string|number = 1;
- numOrStr = 'a'
- // ok
- 复制代码
在 TypeScript 中有两种方式来声明一个数组类型:
根据项目规范二选一(如果没有这个规范可以随便写)
- const arr1: string[] = []; // 可以向数组内添加string类型的值
- const arr2: Array<string> = [];
- 复制代码
类型收敛——元组
场景1 基本类型元组定义
或许我们想定义一个数组来描述三家公司的名称(只有那三家,没有第四家,也不会只有两家),公司名是string,长度是3。但是我们声明string[]就是有问题的,因为他不够收敛。这个时候我们就可以使用元组了。
形式 [typeofmember1, typeofmember2,typeofmember3]
元组声明:[string,string,string]
- const companyArr: [string,string,string] = ['公司n1', '公司n2', '公司n3'];
- 复制代码
场景2 字面量类型元组定义
或许我们想定义一个数组来描述三家优秀公司的名称(NIO,小鹏,理想) 元组声明:['NIO','小鹏','理想']
- const companyArr1: ['NIO','小鹏','理想'] = ['NIO','小鹏','理想'];
- 复制代码
在这种情况下,对数组合法边界内的索引访问(即companyArr1[0],companyArr1[1],companyArr1[2])将能够安全的返回我们理想中的哪三颗韭菜。
场景3 元组类型的 Rest 使用
或许我们想定义一个数组来定义一个人前三项分别为姓名,年龄,性别,后面可以添加若干项描述。这时候我们就可以引入Rest,语法如同js一样,三个点。 元组声明:[string,number,string,...string[]]
- const Person: [string, number, string, ...string[]] = ['shixin', 22, '男', 'JV', '前端'];
- 复制代码
但是问题来了, [string, number, string, ...string[]]未免太难理解了,我怎么知道哪一项代表了哪个信息。在TS4.0添加了元素。操作如下
- const Person: [name:string, age:number,sex:string,...desc:string[]] = ['shixin', 22, '男', 'JV', '前端'];
- 复制代码
对于上面的元组场景3(定义一个数组来定义一个人前三项分别为姓名,年龄,性别)毕竟不是我们的常规操作,更加常见的是我们通过定义一个对象来完成对于一个人的定义。那么如何描述一个对象呢?
内联注解
我们可以如同基本类型一样直接在声明后面添加对象的类型描述
- const shixin: { name: string; age: number; sex: string; desc: string[] } = {
- name: 'shixin',
- age: 22,
- sex: '男',
- desc: ['JV', '前端']
- };
- 复制代码
接口 interface
或通过interface来声明一个类型变量,在变量内进行对象的类型描述
- interface IPerion {
- name: string;
- age: number;
- sex: string;
- desc: string[];
- }
-
- const shixin: IPerion = {
- name: 'shixin',
- age: 22,
- sex: '男',
- desc: ['JV', '前端']
- };
- 复制代码
这样声明的好处,最直接的就是可以复用,这对于我们维护和统一类型起源非常有帮助。
- import { type IPerion } from 'xxx';
-
- const zhang3: IPerion = {
- name: 'zhang3',
- age: 20,
- sex: '男',
- desc: ['xx', 'xx']
- };
-
- 复制代码
object、Object 以及 { }
Object用于描述一个对象,就是万物皆为对象的那个对象。在js中他包含了原始的功能,比如谁都有的toString。也正因为如此,这个属性其实并不好用。甚至有点像any。
- let data1: Object = 'a'; // That's OK
- let data2: Object = 1;// That's OK
- let data3: Object = () => {};// That's OK
- 复制代码
为了解决上面这个不好用的Object,在(typescript2.2)] 引入了object type以表示不含原始类型(number,string,symbol等等)的object类型
- const data1:object = 42; // Error
- const data2:object = 'string'; // Error
- const data3:object = false; // Error
- const data4:object = undefined; // Error
- const data5:object = { prop: 0 }; // OK
- 复制代码
{},一个空对象。你可以在该类型初始化的时候赋予各种各样的值,如同上面的第一个Object。但是在赋值的时候却比较麻烦。
- const data1: {} = { foo: 1 }; // OK
- data1.baz = 2;// Error
- 复制代码
或许这样看起来并不常见,那么这个呢。
- const obj = {};
- 复制代码
事实上,这种定义的方式会讲{}推导为变量obj的类型。在javascript时期,这行代码随处可见。以至于在ts的代码中,依然会有非常多的这种写法,从而出现了下面这些代码.
- const obj = {};
- // 添加一个属性
- obj.foo = 1; //类型“{}”上不存在属性“foo”。
-
- // ⬇
-
- /**
- * 给个初始值
- */
- const obj1 = {
- foo: undefined
- };
- obj1.foo = 1; //不能将类型“1”分配给类型“undefined”。
-
- // ⬇
-
- /**
- * 分支1:给个初始类型undefined
- */
- const obj: {
- foo: undefined | number;
- } = {
- foo: undefined
- };
- obj.foo = 1;
-
- /**
- * 分支2:把foo初始为-1
- */
- const obj = {
- foo: -1
- };
- obj.foo = 1;
- 复制代码
除了object之外,其他两种方式其实在初始化变量的时候非常的开放,对于类型基本没有收敛。所以我们更建议不要使用。而object实际上对变量的描述并不够细致,通常对于对象的创建,我们都能够预想到对象的内容,所以我们更倾向于使用interface接口来定义对象。
枚举的作用和定义形式像一个简单的键值一一对应的map
- const CaseMap = {
- case1: 'Im case1',
- case2: 'Im case2'
- };
-
- enum CaseMap {
- case1 = 'Im case1',
- case2 = 'Im case2'
- }
- 复制代码
如果你没有声明枚举的值,它会默认使用数字枚举,并且从 0 开始。
- const Direction = {
- Up: 0,
- Down: 1,
- Left: 2,
- Right: 3
- };
-
- enum Direction {
- Up,
- Down,
- Left,
- Right
- }
- 复制代码
如果你希望数字枚举从 1 开始,只需要在第一项枚举值声明起始值,那么接下来的项都会递增。
- enum Direction {
- Up = 1,
- Down,
- Left,
- Right
- }
- 复制代码
对于枚举和对象的区别,也很简单,枚举是双向的,对象是单向映射的。原理很简单,我们将上面Direction编译为js,编译产物如下。
- "use strict";
- var Direction;
- (function (Direction) {
- Direction[Direction["Up"] = 1] = "Up";
- Direction[Direction["Down"] = 2] = "Down";
- Direction[Direction["Left"] = 3] = "Left";
- Directi