TypeScript

TypeScript

  • 开始
  • 官方文档
  • 语言规范

›手册

文档说明

  • 文档约定
  • 历史版本

入门指南

  • 五分钟速览

手册

  • 数据类型
  • 变量声明
  • 接口
  • 类
  • 函数
  • 泛型
  • 枚举
  • 类型推断
  • 类型兼容
  • 高级类型

高级类型

交集类型

交集类型(Intersection Type)将多个类型合并为一个类型。这种方式允许你把现有的所有类型合并到一个类型中,且该类型有你需要的所有功能。例如,Person & Serializable & Loggable 是 Person,也是 Serializable,还是 Loggable。这意味着这个类型的实例将拥有三种类型的所有成员。

你通常会在 mixin 类型以及面向对象模型不适合的地方看到交集类型的使用(JavaScript 中有很多这种功能!)。下面是一个 mixin 的列子。

function extend<First, Second>(first: First, second: Second): First & Second {
    const result: Partial<First & Second> = {};
    for (const prop in first) {
        if (first.hasOwnProperty(prop)) {
            (result as First)[prop] = first[prop];
        }
    }
    for (const prop in second) {
        if (second.hasOwnProperty(prop)) {
            (result as Second)[prop] = second[prop];
        }
    }
    return result as First & Second;
}

class Person {
    constructor(public name: string) { }
}

interface Loggable {
    log(name: string): void;
}

class ConsoleLogger implements Loggable {
    log(name) {
        console.log(`Hello, I'm ${name}.`);
    }
}

const jim = extend(new Person('Jim'), ConsoleLogger.prototype);
jim.log(jim.name);

联合类型

联合类型和上面提到的交集类型有点类似,但它们的用法完全不一样。有时候你会遇到一个期望参数既可以是数字又可以是字符串的库。例如,下面这个函数:

/**
 * Takes a string and adds "padding" to the left.
 * If 'padding' is a string, then 'padding' is appended to the left side.
 * If 'padding' is a number, then that number of spaces is added to the left side.
 */
function padLeft(value: string, padding: any) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${padding}'.`);
}

padLeft("Hello world", 4); // returns "    Hello world"

padLeft 函数的问题在于 padding 参数的类型是 any,也就是说我们在调用函数时为 padding 设置的值可以既不是 number 也不是 string,但是 TypeScript 认为代码是没有问题的。

let indentedString = padLeft("Hello world", true); // passes at compile time, fails at runtime.

在传统的面向对象代码中,我们可以通过创建类型的层次结构来抽象化这两种类型。虽然这种方式更为明确,但也有点小题大做了。padLeft 原始版本中我们可以传递基础类型,这是好事。这也就意味着函数的用法简洁明了。如果已经有其他函数解决这个问题,那下面说的新方法也就没多大用处了。

与使用 any 不同,我们将 padding 参数声明为联合类型。

/**
 * Takes a string and adds "padding" to the left.
 * If 'padding' is a string, then 'padding' is appended to the left side.
 * If 'padding' is a number, then that number of spaces is added to the left side.
 */
function padLeft(value: string, padding: string | number) {
    // ...
}

let indentedString = padLeft("Hello world", true); // errors during compilation

联合类型表示声明的变量或传递的参数的类型可以是多个类型中的任意一个,我们可以使用 | 来将每个类型分开,所以类型 number | string | boolean 的值的类型可以是三种类型中的任意一种。

如果我们有一个联合类型的值,我们只能访问在联合体中对所有类型都通用的属性。

interface Bird {
    fly();
    layEggs();
}

interface Fish {
    swim();
    layEggs();
}

function getSmallPet(): Fish | Bird {
    // ...
}

let pet = getSmallPet();
pet.layEggs(); // okay
pet.swim();    // errors

联合类型这样看起来会有些麻烦,但习惯就好了。如果 a 的类型是 A | B,我们只能确认 a 具有 A 和 B 都有的成员。在这个例子中,Bird 有 fly 成员,但我们不能确认联合类型 Bird | Fish 就会有 fly 方法。如果在运行时变量的类型是 Fish,那我们调用 pet.fly() 就会失败。

类型保护和区分类型

联合类型对在建模时值可以互相重叠的情形非常有用,当我们需要明确知道我们是否有一个 Fish 类型的变量时会发生什么呢?JavaScript 中区分两个可能值的常见用法是检查成员是否存在。正如我们提到的,你只能访问联合类型的所有类型都具有的成员属性。

let pet = getSmallPet();

// Each of these property accesses will cause an error
if (pet.swim) {
    pet.swim();
}
else if (pet.fly) {
    pet.fly();
}

为了使以上代码正常工作,我们需要使用类型断言。

let pet = getSmallPet();

if ((pet as Fish).swim) {
    (pet as Fish).swim();
} else if ((pet as Bird).fly) {
    (pet as Bird).fly();
}

用户自定义类型保护

使用类型断言

使用 in 操作符

typeof 类型防护

instanceof 类型防护

空值类型

可选参数和属性

类型保护和类型断言

类型别名

接口 vs. 类型别名

文本字面量类型

数字字面量类型

枚举成员类型

Discriminated Unions

Exhaustiveness checking

多态 this 类型

索引类型

索引类型和索引标识符

映射类型

映射类型推断

条件类型

Distributive conditional types

条件类型的类型推断

预定义条件类型

← 类型兼容Next →
  • 交集类型
  • 联合类型
  • 类型保护和区分类型
    • 用户自定义类型保护
    • typeof 类型防护
    • instanceof 类型防护
  • 空值类型
    • 可选参数和属性
    • 类型保护和类型断言
  • 类型别名
    • 接口 vs. 类型别名
  • 文本字面量类型
  • 数字字面量类型
  • 枚举成员类型
  • Discriminated Unions
    • Exhaustiveness checking
  • 多态 this 类型
  • 索引类型
    • 索引类型和索引标识符
  • 映射类型
    • 映射类型推断
  • 条件类型
    • Distributive conditional types
    • 条件类型的类型推断
    • 预定义条件类型
Copyright © 2025 unimits