extends

在 TypeScript 中,extends 是一个关键字,主要用于继承、约束类型或在条件类型中进行类型推断。它有多种用法,具体取决于上下文。

继承类(Class Inheritance)

extends 用于继承类,表示一个类可以继承另一个类的属性和方法。

class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a sound`);
  }
}

class Dog extends Animal {
  breed: string;
  constructor(name: string, breed: string) {
    super(name);
    this.breed = breed;
  }

  speak() {
    console.log(`${this.name} barks`);
  }
}

const dog = new Dog("Rex", "Labrador");
dog.speak(); // Rex barks

在这个例子中,Dog 类继承了 Animal 类,Dog 可以访问 Animal 的构造函数和方法。

接口继承(Interface Inheritance)

extends 也用于接口,表示一个接口可以继承另一个接口的属性和方法。

interface Animal {
  name: string;
  speak(): void;
}

interface Dog extends Animal {
  breed: string;
}

const dog: Dog = {
  name: "Rex",
  breed: "Labrador",
  speak() {
    console.log(`${this.name} barks`);
  }
};

这里,Dog 接口继承了 Animal 接口,使得 Dog 接口包含了 Animal 接口的所有属性和方法。

类型约束(Type Constraints)

extends 也可以用在泛型类型中,用于限制泛型类型的约束,即只允许继承自某个类型的类型作为参数。

function identity<T extends number | string>(value: T): T {
  return value;
}

identity(42); // 允许
identity("hello"); // 允许
identity(true); // 错误: 类型 'boolean' 不满足约束 'number | string'

在上面的例子中,T extends number | string 表示 T 类型必须是 numberstring,如果传入其他类型,则会报错。

条件类型中的 extends(Conditional Types)

extends 还可以用于条件类型,根据类型是否满足某个条件来决定返回的类型。

type IsString<T> = T extends string ? "Yes" : "No";

type A = IsString<string>;  // "Yes"
type B = IsString<number>;  // "No"

在这个例子中,IsString 是一个条件类型,判断 T 是否是 string 类型。如果是,返回 "Yes";否则返回 "No"

联合类型和交叉类型的 extends

extends 还可以用于检查类型之间的关系,特别是在联合类型和交叉类型中。

type A = { a: string };
type B = { a: string; b: number };

type C = A extends B ? "Yes" : "No";  // "No"
type D = B extends A ? "Yes" : "No";  // "Yes"

在这个例子中,A 并不继承自 B,所以 C 类型是 "No"。而 B 继承了 A(因为 B 包含 A 的所有属性),所以 D 类型是 "Yes"

映射类型中的 extends

extends 还常用于映射类型中,通过类型推导来修改现有类型。

type MyType<T> = {
  [P in keyof T]: T[P] extends string ? string : number;
};

type Example = MyType<{ name: string; age: number }>;
// Example -> { name: string; age: number }

在这个例子中,MyType 是一个映射类型,它根据 T 的属性类型来决定映射后的类型:如果属性类型是 string,则映射成 string;否则映射成 number

总结

extends 在 TypeScript 中有多种用法:

  • 类继承:继承一个类的属性和方法。

  • 接口继承:继承接口的属性和方法。

  • 类型约束:限制泛型类型的约束。

  • 条件类型:基于条件选择返回不同的类型。

  • 联合与交叉类型:判断一个类型是否继承自另一个类型。

  • 映射类型:根据类型条件映射属性类型。

extends 是 TypeScript 中一个非常强大的关键字,它让类型系统变得更加灵活和强大。