🎖️typeScrpt中如何从类派生接口?

简介: 在面向对象编程(OOP)中,通常我们会定义接口,并在不同的类中实现这些接口。但在 TypeScript 中,我们也可以进行反向操作,即从一个类中派生一个接口,而无需实际定义这个接口

嗨,大家好!这里是道长王jj~ 🎩🧙‍♂️

在面向对象编程(OOP)中,通常我们会定义接口,并在不同的类中实现这些接口。但在 TypeScript 中,我们也可以进行反向操作,即从一个类中派生一个接口,而无需实际定义这个接口。这种做法在多种场景下非常有用,比如为 JavaScript 类创建类型安全的模拟。这能确保模拟类实现了原始类的所有方法,而无需额外定义独立的接口。

提取实例类型

首先,我们需要从类中提取实例类型。默认情况下,当你在 TypeScript 中检索类的类型时,你会获得类的构造函数类型,而不是该类实例的类型。为了获得实例类型,我们可以定义一个实用型:

type ExtractInstanceType<T> = T extends new (...args: any[]) => infer R ? R : T extends {
    prototype: infer P } ? P : any;

这里的 ExtractInstanceType<T> 首先尝试从类的构造函数中推断实例类型。如果构造函数不可公开访问,它会从类的原型属性中推断实例类型。这与 TypeScript 内置的 InstanceType<T> 工具类型的主要区别在于,后者只适用于公开的构造函数。

考虑以下带有私有构造函数的类:

class SomeClass {
   
  private constructor() {
   }
  someMethod() {
   }
}

//> OK: 类型为 SomeClass
type SomeClassInstance = ExtractInstanceType<typeof SomeClass>; 

//> Error: 类型 'typeof SomeClass' 无法满足约束 'abstract new (...args: any) => any'。
type SomeClassInstanceError = InstanceType<typeof SomeClass>

从实例类型中提取方法

一旦我们有了实例类型,我们可以提取出它的方法。为此,我们可以定义另外两个实用型:

type ExtractMethodNames<T> = {
    [K in keyof T]: T[K] extends (...args: any[]) => any ? K : never }[keyof T];
type ExtractMethods<T> = Pick<T, ExtractMethodNames<T>>;

ExtractMethodNames<T> 是一个映射类型,它遍历 T 的所有属性,并检查每个属性是否对应于一个方法。如果是方法,则保留该属性的键;否则,将该键分配为 never 类型。

ExtractMethods<T> 利用 Pick 工具类型从 T 中仅选择那些属于方法的属性。

现在,让我们使用这些实用型从 SomeClassInstance 中提取方法:

type SomeClassMethods = ExtractMethods<SomeClassInstance>;

在这个示例中,SomeClassMethods 是仅包含 SomeClass 实例方法的类型。

使用提取的方法实现类

最后,我们来看看如何定义一个实现了 SomeClassMethods 类型的新类。通过确保类的类型为 SomeClassMethods,我们可以确保该类具有与 SomeClass 实例相同的方法。

//> OK: 类实现了 SomeClass 中的方法
class SomeClassMock implements SomeClassMethods {
   
  someMethod() {
   }
}

//> Error: 类 'SomeClassMockError' 不正确地实现了接口 'SomeClassMethods'。
//> 类型 'SomeClassMockError' 中缺少属性 'someMethod',但在类型 'SomeClassMethods' 中是必需的
class SomeClassMockError implements SomeClassMethods {
   
  anotherMethod() {
   }
}

在这段代码中,SomeClassMock 是一个实现了 SomeClassMethods 类型的新类。这确保了 SomeClassMock 包含了 someMethod 函数。如果 SomeClassMock 不包含 someMethod 函数,或者 SomeClassMock 中的 someMethod 函数与 SomeClassMethods 中的函数不匹配,TypeScript 将引发编译错误。🛠️


🎉 你觉得怎么样?这篇文章可以给你带来帮助吗?当你处于这个阶段时,你发现什么对你帮助最大?如果你有任何疑问或者想进一步讨论相关话题,请随时发表评论分享您的想法,让其他人从中受益。🚀✨

目录
相关文章
|
6月前
在实现链表的代码中,为什么要使用继承而不是组合?
在实现链表的代码中,为什么要使用继承而不是组合?
36 3
|
6月前
|
存储 C++
c++类和对象一对象特性一成员变量和成员函数分开存储
c++类和对象一对象特性一成员变量和成员函数分开存储
38 0
🎖️typeScrpt中如何使用条件类型和泛型?
我将通过一个可能对日常使用非常有帮助的代码示例更深入地介绍泛型。
72 1
|
Java
Java多态的本质—动态分派
Java多态的本质—动态分派
117 0
Java多态的本质—动态分派
|
算法 Java 编译器
如何理解对象赋值给接口的操作(关键在对象!)
如何理解对象赋值给接口的操作(关键在对象!)
如何理解对象赋值给接口的操作(关键在对象!)
接口vs抽象类、继承vs组合,他们之间有啥关系
接口vs抽象类、继承vs组合,他们之间有啥关系
普通类,抽象类和接口之间的区别
普通类,抽象类和接口之间的区别
|
Java
抽象类和接口的区别(通俗易理解)
抽象类和接口的区别(通俗易理解)
517 0
C++ 继承与派生中的赋值兼容规则问题探究
C++ 继承与派生中的赋值兼容规则问题探究
177 0
C++ 继承与派生中的赋值兼容规则问题探究
C#(二十二)之抽象方法 密封方法 base new 关键字
本篇内容记录了普通方法的隐藏(new)、base关键字、抽象类和抽象方法(abstract)、密封类和蜜蜂方法(sealed)的简单用法。
129 0
C#(二十二)之抽象方法 密封方法 base new 关键字