TS extends 关键字详解:从类型继承到类型约束

在 TypeScript 的类型系统中,extends 是一个非常核心、但又容易让人混淆的关键字。它既能表示“继承”,又能表示“约束”,甚至还能用来实现“条件类型”。
本文将通过多个层次的示例,帮你彻底搞懂 extends 的用法。


一、extends 在类中的用法:继承实现

在面向对象编程(OOP)中,extends 用于类的继承,表示子类继承父类的属性和方法。

class Animal {
  move() {
    console.log("Moving...");
  }
}

class Dog extends Animal {
  bark() {
    console.log("Woof!");
  }
}

const dog = new Dog();
dog.move(); // ✅ 从 Animal 继承
dog.bark(); // ✅ 自身方法

✅ 小结:在类中,extends 表示继承关系,让子类拥有父类的特性。


二、extends 在接口中的用法:接口继承

接口的继承与类类似,用于组合多个类型的约束。

interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

const d: Dog = {
  name: "Buddy",
  breed: "Golden Retriever",
};

✅ 小结:在接口中,extends 表示类型扩展,相当于多个接口的合并。


三、extends 在泛型中的用法:类型约束(Type Constraint)

在泛型中,extends 用来约束泛型参数的范围
例如,你想让某个泛型 T 只能是“具有 length 属性的类型”:

function getLength<T extends { length: number }>(arg: T): number {
  return arg.length;
}

getLength("hello"); // ✅ string 有 length
getLength([1, 2, 3]); // ✅ 数组有 length
getLength(123); // ❌ number 没有 length

✅ 小结:在泛型中,extends 表示“T 必须符合某个结构”。


四、extends 在条件类型中的用法:类型分发(Conditional Types)

extends 还能用于条件类型中,起到“类型分支”的作用。

语法如下:

T extends U ? X : Y

含义是:“如果 T 可以赋值给 U,则结果为 X,否则为 Y。”

举例:

type IsString<T> = T extends string ? true : false;

type A = IsString<string>;  // true
type B = IsString<number>;  // false

再看一个常见例子——提取 Promise 的结果类型:

type UnwrapPromise<T> = T extends Promise<infer R> ? R : T;

type A = UnwrapPromise<Promise<number>>; // number
type B = UnwrapPromise<string>; // string

(看不太懂,不知干嘛用的😳)

✅ 小结:条件类型结合 extends 可以实现类型推断类型逻辑判断,是 TypeScript 类型编程的核心。


五、extends 与联合类型的“分发行为”

extends 用于联合类型时,会触发 分发条件类型(Distributive Conditional Types)

type ToArray<T> = T extends any ? T[] : never;

type Result = ToArray<string | number>; 
// 相当于 (string extends any ? string[] : never) | (number extends any ? number[] : never)
// 结果为 string[] | number[]

这种行为非常强大,但有时也会带来意想不到的结果。
如果你不想触发分发,可以将类型包裹在方括号中:

type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type Result2 = ToArrayNonDist<string | number>; // (string | number)[]

✅ 小结:使用方括号 [T] extends [U] 可以避免类型分发。


六、总结

用法场景 示例 含义
类继承 class Dog extends Animal 子类继承父类
接口继承 interface Dog extends Animal 接口扩展
泛型约束 <T extends { length: number }> 限制泛型类型结构
条件类型 T extends U ? X : Y 类型逻辑判断
分发行为 T extends any ? ... 联合类型分支推断

七、思考:extends 的哲学

可以把 extends 理解为 TypeScript 类型系统中的一句话:

“A 是 B 的一种吗?”

当答案是“是”时,编译器允许类型兼容、继承或执行某种逻辑;当答案是“否”时,就会触发类型错误或走另一条逻辑分支。


结语

extends 看似简单,却几乎贯穿了 TypeScript 类型系统的各个角落。
它既能用于面向对象的继承,也能支撑类型编程的逻辑判断。
理解它的不同语义,是迈向高级 TypeScript 编程的必经之路。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐