关于 typescript 中 extends 的理解

typescript extends 关键字的基本用法

1. 泛型约束

在泛型中,extends 用于约束类型参数必须是某个类型或其子类型。这是 TypeScript 中一种使用 extends 的常见方式。

例子:泛型中的 extends

scala 复制代码
type MyType<T extends number> = { value: T };

let numType: MyType<number> = { value: 42 };  // 正确
// let strType: MyType<string> = { value: "hello" };  // 错误,因为 string 不符合 extends number 约束

例子:条件类型中的 extends

typescript 复制代码
type MyConditionalType<T> = T extends string ? number : boolean;
let result1: MyConditionalType<string> = 42; // number
let result2: MyConditionalType<boolean> = true; // boolean

2. 接口继承

在接口中,extends 用于声明一个接口继承另一个接口。这样,新的接口将包含父接口的成员,并可以添加额外的成员。

typescript 复制代码
interface Animal {
  name: string;
  makeSound(): void;
}

interface Dog extends Animal {
  bark(): void;
}

const myDog: Dog = {
  name: 'Buddy',
  makeSound() {
    console.log(this.name + ' makes a sound');
  },
  bark() {
    console.log(this.name + ' barks');
  }
};

在这个例子中,Dog 接口通过 extends 继承了 Animal 接口的属性和方法。

需要注意的是,在 TypeScript 中的 extends 主要用于类型系统中的约束和声明继承关系,并不会在运行时创建真正的类继承关系。 TypeScript 的继承更多地关注于类型的静态检查,而不是在运行时创建对象之间的实际继承链。

extends 用于约束类型参数必须是某个类型或其子类型

这句话是什么意思呢?我来解释一下:

当在 TypeScript 中使用 extends 关键字作为类型参数的约束时,意味着该类型必须是指定类型或该类型的子类型。让我们通过一个例子来说明:

typescript 复制代码
// 定义一个基础类型
interface Animal {
    name: string;
}

// 通过扩展基础类型创建一个子类型
interface Dog extends Animal {
    breed: string;
}

// 泛型类型,约束类型参数必须是 Animal 或其子类型
type MyType<T extends Animal> = {
    animalData: T;
    sound(): void;
};

// 使用一个子类型
const dogData: Dog = { name: 'Buddy', breed: 'Labrador' };

// 使用具有子类型的泛型类型
const myDogType: MyType<Dog> = {
    animalData: dogData,
    sound() {
        console.log(`${dogData.name} 会叫`);
    }
};

myDogType.sound(); // 输出 "Buddy 会叫"

在这个例子中:

  • Animal 是一个基础类型。
  • DogAnimal 的子类型,因为它扩展了 Animal
  • MyType 是一个泛型类型,它接受类型参数 T,该参数必须是 Animal 或其子类型。

当我们使用 MyType<Dog> 时,我们在说 TDogDog 的子类型。这是有效的,因为 DogAnimal 的子类型,满足了约束条件。

因此,在这个例子中,子类型是指任何扩展或继承指定基础类型(在这里是 Animal)的类型。

typescript 中的 extends 和 js 中class 的extends 有什么区别?

虽然 TypeScript 中的 extends 关键字与 JavaScript 中的 classextends 关键字在表面上看起来相似,但它们实际上有不同的用途和含义。

TypeScript 中的 extends

在 TypeScript 中,extends 用于类型系统中的泛型和条件类型。在泛型中,extends 用于约束一个类型参数必须是某个类型或其子类型。在条件类型中,extends 用于进行条件判断,根据某个条件选择不同的类型。

例子:泛型中的 extends

scala 复制代码
type MyType<T extends number> = { value: T };
let numType: MyType<number> = { value: 42 }; // 正确
// let strType: MyType<string> = { value: "hello" }; // 错误,因为 string 不符合 extends number 约束

例子:条件类型中的 extends

typescript 复制代码
type MyConditionalType<T> = T extends string ? number : boolean;
let result1: MyConditionalType<string> = 42; // number
let result2: MyConditionalType<boolean> = true; // boolean

JavaScript 中的 extends

在 JavaScript 中的 class 关键字的 extends 用于实现类的继承。子类继承父类的属性和方法,并且可以添加自己的属性和方法。

例子:JavaScript 中的类继承

javascript 复制代码
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + ' makes a sound');
  }
}

class Dog extends Animal {
  speak() {
    console.log(this.name + ' barks');
  }
}

const myDog = new Dog('Buddy');
myDog.speak(); // 输出 "Buddy barks"

在这个例子中,Dog 类继承自 Animal 类,使用了 extends 关键字。

总结:

  • TypeScript 中的 extends 主要用于泛型约束和条件类型,是用于类型系统的。
  • JavaScript 中的 extends 用于类继承,是用于实现面向对象的类继承的。

虽然与 JavaScript 中的 classextends 有些相似之处,但在 TypeScript 中的 extends 不涉及实际的运行时继承

什么是运行时继承呢?

运行时继承指的是在程序实际运行时,一个对象能够继承另一个对象的属性和方法。这是面向对象编程中的一个概念,其中一个类(或构造函数)的实例能够继承另一个类的实例的特性。在传统的面向对象语言中,如Java、C++、Python等,继承是在运行时创建对象之间的实际关联和共享属性与方法。

具体来说,当一个类继承另一个类时,它获得了父类的属性和方法,并且可以通过运行时创建的对象来访问和调用这些继承的成员。这样的继承关系在程序执行时动态地影响着对象之间的关系。

在JavaScript中,classextends 关键字可以用于实现运行时继承。以下是一个简单的例子:

javascript 复制代码
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(this.name + ' makes a sound');
  }
}

class Dog extends Animal {
  bark() {
    console.log(this.name + ' barks');
  }
}

const myDog = new Dog('Buddy');
myDog.speak(); // 输出 "Buddy makes a sound"
myDog.bark();  // 输出 "Buddy barks"

在这个例子中,Dog 类继承了 Animal 类,创建 myDog 对象后,myDog 实例既有 Dog 类的 bark 方法,也有 Animal 类的 speak 方法。这是典型的运行时继承。

相比之下,TypeScript 中的 extends 关键字主要用于静态类型检查,不会在实际运行时创建对象之间的真正继承链。TypeScript 中的继承更关注于在编译阶段进行类型检查,以确保代码的类型安全性。所以,虽然 TypeScript 提供了 extends 关键字,但它不会在运行时创建类继承关系,而是在编译时进行类型检查。

相关推荐
世界哪有真情2 小时前
拿人类意识卡 AI?等于用 bug 验收正式产品
前端·人工智能·后端
Listen·Rain2 小时前
Vue3:setup详解
前端·javascript·vue.js
Patrick_Wilson3 小时前
修好 bug 只是开始:一次由监控需求反向重构日志结构的复盘
前端·监控·数据可视化
kyriewen4 小时前
面试官让我优化一个卡死的表格,我打开 Claude 五秒重写,他放下咖啡问我要不要来当组长
前端·javascript·面试
小粉粉hhh4 小时前
React(二)——dom、组件间通信、useEffect
前端·javascript·react.js
Csvn4 小时前
🤖 AI 生成前端代码的 5 个典型翻车现场及修复指南
前端
IT_陈寒5 小时前
SpringBoot自动装配坑了我一天,原来问题出在这
前端·人工智能·后端
索西引擎6 小时前
【React】key 属性:协调算法中的元素标识机制与最佳实践
前端·javascript·react.js
只会cv的前端攻城狮7 小时前
动态组件架构设计:从配置到事件驱动全链路解析
前端·vue.js
飞天狗7 小时前
Next.js 16 App Router 实战:服务端组件与流式渲染
前端·next.js