Typescript 子 class 函数重载
Typescript child class function overloading
如何在打字稿中实现类似于此模式的内容?
class A {
Init(param1: number) {
// some code
}
}
class B extends A {
Init(param1: number, param2: string) {
// some more code
}
}
上面截取的代码看起来应该可以工作,但是在仔细检查 How Typescript function overloading works 后发现抛出错误是有道理的:
TS2415: 'Class 'B' incorrectly extends base class 'A'.
Types of property 'Init' are incompatible.
我知道构造函数允许这种行为,但我不能在这里使用构造函数,因为这些对象被合并以提高内存效率。
我可以在 class A:
中提供 Init() 的另一个定义
class A {
Init(param1: number, param2: string): void;
Init(param1: number) {
// some code
}
}
然而,这并不理想,因为现在基础 class 需要了解其派生的所有 classes。
第三种选择是重命名 class B 中的 Init 方法,但这不仅会非常丑陋和令人困惑,而且会暴露基础 class 中的 Init() 方法,当基础 class Init() 被错误调用时,这将导致难以检测的错误。
有没有什么方法可以实现这种模式而不存在上述方法的缺陷?
TypeScript 抱怨方法不可互换:如果您执行以下操作会发生什么?
let a:A = new A(); // a is of type A
a.Init(1)
a = new B(); // a is still of type A, even if it contains B inside
a.Init(1) // second parameter is missing for B, but totally valid for A, will it explode?
如果您不需要它们可以互换,请修改 B
的签名以符合 A
的签名:
class B extends A {
Init(param1: number, param2?: string) { // param 2 is optional
// some more code
}
}
但是,您可能会发现自己处于需要创建具有完全不同方法签名的 class 的情况:
class C extends A {
Init(param1: string) { // param 1 is now string instead of number
// some more code
}
}
在这种情况下,添加满足当前 class 和基础 class 调用的方法签名列表。
class C extends A {
Init(param1: number)
Init(param1: string)
Init(param1: number | string) { // param 1 is now of type number | string (you can also use <any>)
if (typeof param1 === "string") { // param 1 is now guaranteed to be string
// some more code
}
}
}
这样 A
class 就不必知道任何派生的 classes。作为权衡,您需要指定满足基础 class 和子 class 方法调用的签名列表。
对于想要扩展类型的人。
基于 , and using Intersection types
interface ConsumerGroup {
on(message: 'message'): void
on(message: 'error'): void
}
interface ConsumerGroup2 {
on(message: 'messageDecoded'): void;
on(message: 'rawMessage'): void;
}
// Intersection types
type ConsumerGroupEx = ConsumerGroup2 & ConsumerGroup;
function newEvent(): ConsumerGroupEx {
return "just for test" as unknown as ConsumerGroupEx;
}
const evt = newEvent();
evt.on('messageDecoded'); // ok
evt.on('message'); // ok
evt.on('error'); // ok
evt.on('notExist'); // compilation error
如何在打字稿中实现类似于此模式的内容?
class A {
Init(param1: number) {
// some code
}
}
class B extends A {
Init(param1: number, param2: string) {
// some more code
}
}
上面截取的代码看起来应该可以工作,但是在仔细检查 How Typescript function overloading works 后发现抛出错误是有道理的:
TS2415: 'Class 'B' incorrectly extends base class 'A'.
Types of property 'Init' are incompatible.
我知道构造函数允许这种行为,但我不能在这里使用构造函数,因为这些对象被合并以提高内存效率。
我可以在 class A:
中提供 Init() 的另一个定义class A {
Init(param1: number, param2: string): void;
Init(param1: number) {
// some code
}
}
然而,这并不理想,因为现在基础 class 需要了解其派生的所有 classes。
第三种选择是重命名 class B 中的 Init 方法,但这不仅会非常丑陋和令人困惑,而且会暴露基础 class 中的 Init() 方法,当基础 class Init() 被错误调用时,这将导致难以检测的错误。
有没有什么方法可以实现这种模式而不存在上述方法的缺陷?
TypeScript 抱怨方法不可互换:如果您执行以下操作会发生什么?
let a:A = new A(); // a is of type A
a.Init(1)
a = new B(); // a is still of type A, even if it contains B inside
a.Init(1) // second parameter is missing for B, but totally valid for A, will it explode?
如果您不需要它们可以互换,请修改 B
的签名以符合 A
的签名:
class B extends A {
Init(param1: number, param2?: string) { // param 2 is optional
// some more code
}
}
但是,您可能会发现自己处于需要创建具有完全不同方法签名的 class 的情况:
class C extends A {
Init(param1: string) { // param 1 is now string instead of number
// some more code
}
}
在这种情况下,添加满足当前 class 和基础 class 调用的方法签名列表。
class C extends A {
Init(param1: number)
Init(param1: string)
Init(param1: number | string) { // param 1 is now of type number | string (you can also use <any>)
if (typeof param1 === "string") { // param 1 is now guaranteed to be string
// some more code
}
}
}
这样 A
class 就不必知道任何派生的 classes。作为权衡,您需要指定满足基础 class 和子 class 方法调用的签名列表。
对于想要扩展类型的人。
基于
interface ConsumerGroup {
on(message: 'message'): void
on(message: 'error'): void
}
interface ConsumerGroup2 {
on(message: 'messageDecoded'): void;
on(message: 'rawMessage'): void;
}
// Intersection types
type ConsumerGroupEx = ConsumerGroup2 & ConsumerGroup;
function newEvent(): ConsumerGroupEx {
return "just for test" as unknown as ConsumerGroupEx;
}
const evt = newEvent();
evt.on('messageDecoded'); // ok
evt.on('message'); // ok
evt.on('error'); // ok
evt.on('notExist'); // compilation error