基本类型
元组 Tuple
类似数组,限制元素数量;
let x: [string, number];
枚举
类似对象,一般用于定义有映射关系的常量
enum StatusEnum { success = 0, danger = 1, warning = 2 }
枚举的便利是既可以通过名字获取枚举值,也可以通过枚举值获取名字
let successVal: StatusEnum = StatusEnum.success; // 0
let successName: string = StatusEnum[0]; // 'success'
联合类型
属性为多种类型之一
基础类型
类似js中的||
使用时,只能访问此联合类型的所有类型里共有的属性或方法
let a: string | number;
a.length // Error:类型“number”上不存在属性“length”
使用typeof作类型保护
let a: string | number;
if (typeof a === 'string') {
// string
a.length; // OK
} else {
//number
}
在赋予变量的值之后,ts会自动推断所属类型,此后只可调用对应类型的方法
对象类型
赋值时,数据结构需满足二者之一的类型结构
interface Student {
name: string;
score: number;
}
interface Teacher {
name: string;
age: number;
}
type User = Teacher | Student
let user: User;
user = {name: 'zs', age: 123};//OK
user = {name: 'zs', score: 123};//ok
下面的情况是可以通过的
let user: User = {name: '张三', age: 18, score: 12};
//只能访问共同属性
user.name;//OK
user.age;//Error
访问属性时,只能访问联合中的共同属性
interface Student {
name: string;
score: number;
}
interface Teacher {
name: string;
age: number;
}
type User = Teacher | Student
let user: User;
user.name; // OK
user.score; // Error类型“Teacher”上不存在属性“score”
user.age; // Error类型“Student”上不存在属性“age”
如果需要访问的是非共同的属性,必须做好类型保护
使用in帮助ts识别类型
interface Student {
name: string;
score: number;
}
interface Teacher {
name: string;
age: string;
}
type User = Teacher | Student
function test(user: User) {
if ('score' in user) { //Student
console.log(user.score);
}else{ //Teacher
console.log(user.age)
}
}
赋值后访问属性
const user: User = { name: 'zs', score: 123 }; // OK
user.name; //OK
user.score;//OK
TS类型兼容性
类型兼容性用于确定一个类型是否能赋值给其他类型。
其基本规则是,如果x
要兼容y
,那么y
至少具有与x
相同的属性。比如:
interface Named {
name: string;
}
let x: Named;
// y's inferred type is { name: string; location: string; }
let y = { name: 'Alice', location: 'Seattle' };
x = y; //ok
交叉类型
用于组合多个类型为一个类型(常用于对象类型),新的类型包含所有类型的特性
接口类型的交叉
交叉后的类型包含所有接口内的属性
interface Student {
name: string;
age: number;
score: number;
}
interface Teacher {
name: string;
age: number;
}
type User = Teacher & Student
//相当于type User = {name: string, age: number, score: number}
let user = {} as User;
user.name;//ok
user.score;//ok
联合类型的交叉
交叉后的类型需满足所有类型,相当于所有类型的交集。
type typeA = 'day' | 'week';
type typeB = 'day' | 'month';
type typeAB = typeA & typeB
那么typeAB的类型为
'day'
如果无法产生交集,则为never类型
type typeA = 'week';
type typeB = 'month';
type typeAB = typeA & typeB; // nerver
同时,在对对象类型进行交叉运算的时候,如果对象中相同的属性被认为是可辨识的属性(即属性的类型是字面量类型或字面量类型组成的联合类型),那么如果此类型不同且没有包含关系,则最终的运算结果将是 never 类型:
type typeA = {name: 'a', age: number};
type typeB = {name: 'b', age: number};
type typeAB = typeA & typeB; // never
函数类型的交叉
使用交叉类型可以将不同参数类型的函数进行合并
type FnA = (a: string) => void;
type FnB = (a: number) => void;
type FnAB = FnA & FnB;
那么FnAB就相当于
(a: string | number) => void
泛型
泛型用于创建可重用的组件,一个组件可以支持多种类型的数据。
一般用于定义一个不确定类型的函数/接口/类型,不预先指定具体的类型,而是在使用的时候在指定类型。 官方示例:
function identity<T>(arg: T): T {
return arg;
}
定义后可使用两种方法指定类型,
第一种,使用<>明确指定类型
let output = identity<string>("myString"); // type of output will be 'string'
第二种,利用类型推论 – 即编译器会根据传入的参数自动地帮助我们确定T的类型:
let output = identity("myString"); // type of output will be 'string'
使用泛型变量时需注意,必须把这些泛型参数当做是任意或所有类型s
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length。函数可能传入的是个数字,而数字是没有 .length属性的
return arg;
}
对于上面的问题,可以通过泛型约束来解决
泛型约束
泛型约束即是对泛型的类型进行约束控制。
对于上面无法访问length属性的情况,我们可以创建一个包含length属性的接口,配合extends关键字实现约束。
interface LengthInterface {
length: number;
}
function loggingIdentity<T>(arg: T extends LengthInterface): T {
console.log(arg.length);// OK
return arg;
}
经过约束之后,传入的值就必须符合约束类型
泛型默认类型
interface A<T = string> {
name: T
}