typescript - 11.高级类型
一、交叉类型(Intersection Types)
核心概念
将多个类型合并为一个类型,包含所有类型的成员,语法为 T & U。适用于混入(mixins)等非典型面向对象场景。
简易代码演示
// 定义基础类型
interface Person {
name: string;
}
interface Loggable {
log(): void;
}
// 交叉类型:同时拥有 Person 和 Loggable 的成员
type PersonWithLog = Person & Loggable;
// 使用交叉类型
const user: PersonWithLog = {
name: "Jim",
log: () => console.log(`姓名:${user.name}`)
};
user.log(); // 输出:姓名:Jim
二、联合类型(Union Types)
核心概念
表示一个值可以是几种类型之一,语法为 T | U。只能访问所有类型的共有成员。
简易代码演示
// 修复原文档的 padLeft 函数,使用联合类型替代 any
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return " ".repeat(padding) + value;
}
return padding + value;
}
// 合法调用
console.log(padLeft("Hello", 4)); // " Hello"
console.log(padLeft("Hello", "###")); // "###Hello"
// padLeft("Hello", true); // 编译报错:布尔值不满足 string | number
// 联合类型的成员访问限制
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
const pet: Bird | Fish = { layEggs: () => {}, fly: () => {} };
pet.layEggs(); // 合法:共有成员
// pet.swim(); // 编译报错:非共有成员
三、类型保护与区分类型(Type Guards and Differentiating Types)
核心概念
通过运行时检查缩小类型范围,解决联合类型“不确定具体类型”的问题,包含三种常用方式:用户自定义类型保护、typeof 类型保护、instanceof 类型保护。
简易代码演示
1. 用户自定义类型保护
interface Bird { fly(): void; layEggs(): void; }
interface Fish { swim(): void; layEggs(): void; }
// 定义类型保护函数,返回值为 "参数 is 类型"
function isFish(pet: Bird | Fish): pet is Fish {
return (pet as Fish).swim !== undefined;
}
// 使用类型保护
const pet: Bird | Fish = { swim: () => {}, layEggs: () => {} };
if (isFish(pet)) {
pet.swim(); // 编译识别为 Fish 类型
} else {
pet.fly(); // 编译识别为 Bird 类型
}
2. typeof 类型保护
function handleValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase()); // 识别为 string
} else {
console.log(value.toFixed(2)); // 识别为 number
}
}
3. instanceof 类型保护
class SpacePadder {
constructor(public numSpaces: number) {}
getPadding() { return " ".repeat(this.numSpaces); }
}
class StringPadder {
constructor(public value: string) {}
getPadding() { return this.value; }
}
const padder = Math.random() > 0.5 ? new SpacePadder(4) : new StringPadder("###");
if (padder instanceof SpacePadder) {
console.log(padder.numSpaces); // 识别为 SpacePadder
} else {
console.log(padder.value); // 识别为 StringPadder
}
四、可以为null的类型
核心概念
启用 --strictNullChecks 后,null/undefined 不能随意赋值给其他类型,需显式声明 T | null/T | undefined;可选参数/属性自动隐含 | undefined;可通过 ! 非空断言去除空值类型。
简易代码演示
// 启用 --strictNullChecks 时
let name: string | null = "Bob";
name = null; // 合法
// name = undefined; // 编译报错:undefined 不属于 string | null
// 可选参数
function fn(x: number, y?: number) {
return x + (y || 0);
}
fn(1, undefined); // 合法
// fn(1, null); // 编译报错:null 不属于 number | undefined
// 非空断言
function getUserName(): string | null {
return "Alice";
}
const userName = getUserName()!; // 断言非空
console.log(userName.charAt(0)); // 合法
五、类型别名
核心概念
给类型起新名字,语法为 type 别名 = 类型,可作用于原始类型、联合类型、泛型等,不创建新类型,仅为别名。与接口的区别:不能被 extends/implements,适合复杂类型(联合、元组)。
简易代码演示
// 基础别名
type Name = string;
// 联合类型别名
type Easing = "ease-in" | "ease-out" | "ease-in-out";
// 泛型别名
type Container<T> = { value: T };
// 递归别名(树形结构)
type Tree<T> = {
value: T;
left?: Tree<T>;
right?: Tree<T>;
};
// 使用
const easing: Easing = "ease-in";
const container: Container<number> = { value: 10 };
六、字符串字面量类型
核心概念
限制字符串为固定值,可与联合类型配合实现枚举效果,也可用于区分函数重载。
简易代码演示
// 字符串字面量联合类型
type Direction = "up" | "down" | "left" | "right";
// 限制函数参数为固定值
function move(direction: Direction) {
console.log(`移动方向:${direction}`);
}
move("up"); // 合法
// move("forward"); // 编译报错:不在 Direction 中
// 用于函数重载
function createElement(tag: "img"): { tag: "img", src: string };
function createElement(tag: "input"): { tag: "input", value: string };
function createElement(tag: string): { tag: string } {
return { tag };
}
const img = createElement("img"); // 类型为 { tag: "img", src: string }
七、数字字面量类型
核心概念
限制数字为固定值,多用于缩小类型范围、调试错误。
简易代码演示
// 数字字面量联合类型
type Die = 1 | 2 | 3 | 4 | 5 | 6;
// 限制函数返回值为固定数字
function rollDie(): Die {
return Math.floor(Math.random() * 6) + 1 as Die;
}
// 类型检查报错示例
function foo(x: number) {
// if (x !== 1 || x !== 2) { // 编译报错:逻辑矛盾
// console.log(x);
// }
}
八、可辨识联合(Discriminated Unions)
核心概念
结合单例类型属性(标签)、联合类型、类型保护的高级模式,也称标签联合。核心要素:唯一的 kind 标签、类型别名联合、标签上的类型保护。
简易代码演示
// 定义带标签的接口
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
// 联合类型
type Shape = Square | Rectangle | Circle;
// 计算面积(通过标签区分类型)
function getArea(shape: Shape): number {
switch (shape.kind) {
case "square": return shape.size ** 2;
case "rectangle": return shape.width * shape.height;
case "circle": return Math.PI * shape.radius ** 2;
// 完整性检查:新增类型时此处会报错
default: throw new Error(`未知形状:${(shape as never).kind}`);
}
}
console.log(getArea({ kind: "square", size: 4 })); // 16
九、多态的 this 类型
核心概念
表示包含类或接口的子类型,实现链式调用,子类继承后仍保持自身类型。
简易代码演示
// 基础计算器类
class BasicCalculator {
constructor(protected value: number = 0) {}
add(num: number): this {
this.value += num;
return this;
}
multiply(num: number): this {
this.value *= num;
return this;
}
getValue(): number {
return this.value;
}
}
// 科学计算器子类
class ScientificCalculator extends BasicCalculator {
sin(): this {
this.value = Math.sin(this.value);
return this;
}
}
// 链式调用
const result = new ScientificCalculator(2)
.multiply(5)
.sin()
.add(1)
.getValue();
console.log(result);
十、索引类型(Index types)
核心概念
通过 keyof T(获取属性名联合)和 T[K](获取属性类型),实现动态属性的类型安全访问。
简易代码演示
interface Person {
name: string;
age: number;
}
// 提取对象的指定属性
function pluck<T, K extends keyof T>(obj: T, keys: K[]): T[K][] {
return keys.map(key => obj[key]);
}
const person: Person = { name: "Jarid", age: 35 };
// 合法:提取 name 和 age
const values = pluck(person, ["name", "age"]);
console.log(values); // ["Jarid", 35]
// pluck(person, ["address"]); // 编译报错:address 不是 Person 的属性
// 获取属性类型
type NameType = Person["name"]; // string
十一、映射类型
核心概念
基于已有类型,批量转换属性的修饰符或类型(如可选、只读)。TypeScript 内置 Partial<T>、Readonly<T>、Pick<T, K>、Record<K, T> 等映射类型,也可自定义。
简易代码演示
interface Person {
name: string;
age: number;
}
// 内置映射类型
type PartialPerson = Partial<Person>; // 所有属性可选
type ReadonlyPerson = Readonly<Person>; // 所有属性只读
type PickPerson = Pick<Person, "name">; // 仅保留 name 属性
type RecordPerson = Record<"id1" | "id2", Person>; // 键值对类型
// 自定义映射类型:所有属性可空
type Nullable<T> = { [P in keyof T]: T[P] | null };
type NullablePerson = Nullable<Person>;
// 使用
const partialPerson: PartialPerson = { name: "Bob" }; // 合法
const nullablePerson: NullablePerson = { name: null, age: 20 }; // 合法
十二、预定义的有条件类型
核心概念
TypeScript 2.8+ 提供的内置有条件类型,基于条件逻辑提取/过滤类型,包括 Exclude、Extract、NonNullable、ReturnType、InstanceType。
简易代码演示
// Exclude:剔除可赋值给 U 的类型
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
// Extract:提取可赋值给 U 的类型
type T1 = Extract<"a" | "b" | "c", "a" | "d">; // "a"
// NonNullable:剔除 null/undefined
type T2 = NonNullable<string | number | null>; // string | number
// ReturnType:获取函数返回值类型
function f1() { return { a: 1, b: "hello" }; }
type T3 = ReturnType<typeof f1>; // { a: number, b: string }
// InstanceType:获取构造函数的实例类型
class C { x = 0; }
type T4 = InstanceType<typeof C>; // C
核心总结
TypeScript 高级类型的本质是通过组合、约束、转换,在保留 JavaScript 动态特性的同时,实现更精细的类型安全控制。核心价值在于:
- 增强代码的可读性和可维护性;
- 提前在编译阶段发现错误;
- 支持复杂的类型逻辑,适配多样化的开发场景。

浙公网安备 33010602011771号