在 TypeScript 里,高级类型是提升类型系统灵活性和表达能力的重要工具,下面介绍常见高级类型及其用法。
交叉类型
通过 & 运算符将多个类型合并为一个类型,新类型包含所有类型的特性。
interface Person {
name: string;
}
interface Employee {
employeeId: number;
}
type PersonEmployee = Person & Employee;
const personEmployee: PersonEmployee = {
name: 'Alice',
employeeId: 123
};
联合类型
通过 | 运算符定义一个值可以是几种类型之一。
function printId(id: number | string) {
console.log(id);
}
printId(123);
printId('a');
类型别名
使用 type 关键字定义类型别名。
type Point = { x: number; y: number };
const point: Point = { x: 1, y: 2
};
类型索引
通过keyof 操作符能获取一个对象类型所有属性名构成的联合类型。
interface Person {
name: string;
age: number;
}
// PersonKey 类型为 "name" | "age"
type PersonKey = keyof Person;
function getProperty(person: Person, key: PersonKey) {
return person[key];
}
const person: Person = { name: 'Alice', age: 30 };
// 正确
const name = getProperty(person, 'name');
// 报错,'phone' 不在 PersonKey 类型中
//const invalid = getProperty(person, 'phone');
类型约束
使用 extends 关键字可以约束泛型类型的取值范围。
约束泛型参数为特定类型
//extends类型约束,这里要求 T 类型必须包含 length 属性
function getLength<T extends { length: number }>(value: T): number {
return value.length;
}
// 正确,字符串有 length 属性
const strLength = getLength('hello');
// 正确,数组有 length 属性
const arrLength = getLength([1, 2, 3]);
// 报错,数字没有 length 属性
//const numLength = getLength(123);
约束泛型参数为对象属性类型
interface Person {
name: string;
age: number;
}
// T 约束为 Person 类型的属性名
function getProperty<T extends keyof Person>(person: Person, key: T): Person[T] {
return person[key];
}
const person: Person = { name: 'Alice', age: 30 };
// 正确
const name = getProperty(person, 'name');
// 正确
const age = getProperty(person, 'age');
// 报错,'phone' 不是 Person 的属性名
// const invalid = getProperty(person, 'phone');
映射类型
通过 in 关键字可以对类型进行映射操作。
语法
type MappedType<T> = {
[P in keyof T]: T[P];
};
可选类型的映射
//将 Person 的所有属性变为可选
interface Person {
name: string;
age: number;
}
type OptionalPerson = { [K in keyof Person]?: Person[K] };
const optionalPerson: OptionalPerson = { name: 'Alice' };
//只读属性映射
interface Point {
x: number;
y: number;
}
只读属性映射
interface Point {
x: number;
y: number;
}
// 将 Point 的所有属性变为只读
type ReadonlyPoint = { readonly [K in keyof Point]: Point[K] };
const readonlyPoint: ReadonlyPoint = { x: 10, y: 20 };
// 报错,属性只读
// readonlyPoint.x = 30;
属性值类型转换
interface NumberConfig {
min: number;
max: number;
}
// 将 NumberConfig 的所有属性值类型转换为 string
type StringConfig = { [K in keyof NumberConfig]: string };
const stringConfig: StringConfig = { min: '0', max: '100' };
条件类型
条件类型是一种强大的类型工具,借助条件表达式来动态确定类型。它的语法类似 JavaScript 中的三元运算符,基本形式为 T extends U ? X : Y。
// 定义一个条件类型,判断 T 是否为数组类型
type IsArray<T> = T extends any[] ? true : false;
// NumberIsArray 类型为 false
type NumberIsArray = IsArray<number>;
// StringArrayIsArray 类型为 true
type StringArrayIsArray = IsArray<string[]>;
//TypeScript中内置工具类型都借助了条件类型实现
// Exclude<T, U>:从 T 中排除可以赋值给 U 的类型
type Exclude<T, U> = T extends U ? never : T;
// NonNullable<T>:从 T 中排除 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;