TS允许我们为变量设置类型限制并进行检测判断
// 常见的类型判断
let age: number = 20;
let isDead: boolean = true;
let name: string = 'abc';
但是上面的写法太啰嗦了。ts有一个类型推断机制,ts会根据为变量赋的值自动给该变量设置一个类型。上面可以写为:
let age = 20;
let isDead = true;
let name = 'abc';
在上面的代码中,ts知道age就是一个数,isDead就是一个布尔值,name就是字符串,不需要显式设置变量类型。
当声明了一个变量但是没有设置初始值,建议为其设置一个类型
let ttt: string;
如果没有设置类型,那么它的类型会被设置为any,即接受任何值。
let isDone: boolean = false;
let count: number = 10;
let name: string = "Semliker";
let list: number[] = [1, 2, 3];
let list: string[] = ['1','2','3']
let list: Array = [1, 2, 3]; // Array泛型语法
至于什么是泛型,请看后面章
function cat(fn: Function) {
fn();
}
cat(function(){console.log('我是一只猫')})
1. 匿名对象类型
匿名对象类型是在定义变量时直接使用花括号{},来定义一个对象类型。例如:
const person: { name: string, age: number } = { name: 'John', age: 25 };
上述代码中定义了一个person变量,它的类型为对象,它有两个属性:name和age,其中name属性的类型为字符串,age属性的类型为数字。
2. 接口类型
使用接口来定义对象类型,可以使代码更加可读、易于维护。例如:
interface Person {name: string;age: number;}
const person: Person = { name: 'John', age: 25 };
上述代码中,定义了一个名为Person的接口,其中包括了两个属性:name和age。然后使用Person接口来定义了一个person变量,它的类型为Person接口。
你喜欢的话甚至可以把键名的类型也给限定了。
interface stringKeyObj {
[key: string]: string;
}
至于什么是接口,请看后面章节
3.类别类型
使用类型别名可以为对象类型定义简短、易读的名称。例如:
type Person = {name: string;age: number;}
const person: Person = { name: 'John', age: 25 };
有点像泛型。
上述代码中,使用type关键字定义了一个名为Person的类型别名,并通过花括号{}来定义了一个对象类型,其中有两个属性:name和age。然后使用Person类型别名来定义了一个person变量,它的类型为Person类型别名。
在 TypeScript 中,任何类型都可以被归为 any 类。也被称作全局超级类型)。使用any类型TS将不会对其进行任何检查。
let notSure: any = 666;
notSure = "Semlinker";
notSure = false;
可以对any类型的值进行任何操作
let value: any;
value.foo.bar; // OK
value.trim(); // OK
value(); // OK
new value(); // OK
value[0][1]; // OK
如果我们使用 any 类型,就无法使用 TypeScript 提供的大量的保护机制。为了解决 any 带来的问题,TypeScript 3.0 引入了 unknown 类型。
所有类型都可以赋值给 unknown。
let value: unknown
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
let value: unknown;
value = 123;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
unknown 类型只能被赋值给 any 类型和 unknown 类型本身。不能赋值给其他类型。
只有能够保存任意类型值的容器才能保存 unknown类型的值。毕竟我们不知道变量 value 中存储了什么类型的值。
let value: unknown;
value.foo.bar; // Error
value.trim(); // Error
value(); // Error
new value(); // Error
value[0][1]; // Error
禁止对unkonwn类型的值进行任何修改操作
TypeScript 支持数字的和基于字符串的枚举。
字符串枚举:
enum DataType {
/** @name 组织 */
Org = 'org',
/** @name 用户 */
User = 'user',
/** @name 角色 */
Role = 'role',
}
let dir: DataType = DataType.Org ;
数字枚举:
enum Direction {
/** 0 */
NORTH,
/** 1 */
SOUTH,
/** 2 */
EAST,
/** 3 */
WEST,
}
let a: Direction = Direction.SOUTH;
let b: Direction = Direction.WEST;
默认情况下,NORTH 的初始值为 0,其余的成员会从 1 开始自动增长。换句话说,Direction.SOUTH 的值为 1,Direction.EAST 的值为 2,Direction.WEST 的值为 3。
注意这个Direction 并不是生成类似于下面这种对象:
Direction = {
NORTH: 0,
SOUTH: 1,
EAST: 2,
WEST: 3,
}
而是:
{0: "NORTH",
1: "SOUTH",
2: "EAST",
3: "WEST",
NORTH: 0,
SOUTH: 1,
EAST: 2,
WEST: 3}
所以转换成JS便是:
var Direction;
(function (Direction) {
/** 0 */
Direction[Direction["NORTH"] = 0] = "NORTH";
/** 1 */
Direction[Direction["SOUTH"] = 1] = "SOUTH";
/** 2 */
Direction[Direction["EAST"] = 2] = "EAST";
/** 3 */
Direction[Direction["WEST"] = 3] = "WEST";
})(Direction || (Direction = {}));
var a = Direction.SOUTH;
var b = Direction.WEST;
Direction[Direction["NORTH"] = 0] = "NORTH";
这个看不懂?
其实就是:
Direction["NORTH"] = 0
Direction[0]="NORTH"
3.异构枚举
异构枚举的成员值是数字和字符串的混合:
enum Enum {
A,
B,
C = "C",
D = "D",
E = 8,
F,
}
JS的习惯性书写,TS的数组类型决定了数组一般由同种类型的值组成。,但有时我们需要在单个变量中存储不同类型的值,这时候我们就可以使用元组。在 JavaScript 中是没有元组的,元组是 TypeScript 中特有的类型,其工作方式类似于数组。
let tupleType: [string, boolean];
tupleType = ["Semlinker", true];
类型检测:
同时也会进行长度检测:
void 类型像是与 any 类型相反,它表示没有任何类型。当一个函数没有返回值时,你通常会见到其返回值类型是 void:
function xxx(): void {
console.log("123");
}
以上代码编译生成的 ES5 :
"use strict";
function xxxx() {
console.log("123");
}
如果用Void类型来定义变量,那么它只能接受undefined的值
undefined 和 null 分别定义为 undefined 类型和 null类型
let u: undefined = undefined;
let n: null = null;
表示的是那些永不存在的值的类型。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
never 类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型。
听起来没什么用。实际上,我们在项目用Never类型进行全面性检查:
type Foo = string | number;
function controlFlowAnalysisWithNever(foo: Foo) {
if (typeof foo === "string") {
// 这里 foo 被收窄为 string 类型
} else if (typeof foo === "number") {
// 这里 foo 被收窄为 number 类型
} else {
// foo 在这里是 never
const check: never = foo;
}
}