🎖️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 将引发编译错误。🛠️


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

目录
相关文章
|
7月前
|
设计模式 存储 Java
JAVA设计模式11:组合模式,以统一的方式处理单个对象和组合对象
JAVA设计模式11:组合模式,以统一的方式处理单个对象和组合对象
|
9月前
|
Java C++
面对对象三大特性:封装、继承、多态
面对对象三大特性:封装、继承、多态
|
11月前
|
编译器 C++
C++ :类 和 对象 ※重点※(二)
C++ :类 和 对象 ※重点※(二)
54 0
|
11月前
|
编译器 C++
C++ :类 和 对象 ※重点※(一)
C++ :类 和 对象 ※重点※
34 0
|
11月前
|
Java 编译器 C++
C++ :类 和 对象 ※重点※(三)
C++ :类 和 对象 ※重点※(三)
62 0
|
安全 Java 程序员
java面向对象的三大特性之封装和继承(配视频讲解)
🍅程序员小王的博客:程序员小王的博客 🍅程序员小王的资源博客:http://wanghj.online/ 🍅 欢迎点赞 👍 收藏 ⭐留言 📝 🍅 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕 🍅java自学的学习路线:java自学的学习路线 ———————————————— 版权声明:本文为CSDN博主「程序员小王java」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_44385486/article/details/128171102
130 0
java面向对象的三大特性之封装和继承(配视频讲解)
|
算法 Java 编译器
如何理解对象赋值给接口的操作(关键在对象!)
如何理解对象赋值给接口的操作(关键在对象!)
如何理解对象赋值给接口的操作(关键在对象!)
|
Java
使用java反射机制读取任意类内部细节
使用java反射机制读取任意类内部细节
118 0
重复动作要封装,封装前找大家的共同特性或者说共同需求(例如都实现某个接口,都实现该接口的某个方法),然后利用这个共同特性封装起来
重复动作要封装,封装前找大家的共同特性或者说共同需求(例如都实现某个接口,都实现该接口的某个方法),然后利用这个共同特性封装起来
108 0
|
Java 数据库 数据安全/隐私保护
规则之间-方法覆写限制 | 带你学《Java面向对象编程》之四十
本节向读者介绍了覆写方法过程中的一些限制,并拓宽读者对访问权限控制符的认识,帮助读者进行有效的方法覆写。