TS extends关键字(类继承、接口继承、类型扩展、泛型类型约束Type Constraint、条件类型分发Conditional Types、分发条件类型)
用法场景示例含义类继承子类继承父类接口继承接口扩展泛型约束限制泛型类型结构条件类型X : Y类型逻辑判断分发行为...联合类型分支推断extends看似简单,却几乎贯穿了 TypeScript 类型系统的各个角落。它既能用于面向对象的继承,也能支撑类型编程的逻辑判断。理解它的不同语义,是迈向高级 TypeScript 编程的必经之路。
文章目录
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 编程的必经之路。
更多推荐
所有评论(0)