Typescript子类函数重载

Dan*_*iel 7 inheritance overloading typescript

如何在打字稿中实现类似于这种模式的东西?

class A {
    Init(param1: number) {
        // some code
    }
}

class B extends A {
    Init(param1: number, param2: string) {
        // some more code
    }
}
Run Code Online (Sandbox Code Playgroud)

上面剪切的代码看起来应该可以正常工作,但是仔细检查一下Typescript函数重载是如何工作的,就会抛出一个错误:

TS2415: 'Class 'B' incorrectly extends base class 'A'. 
Types of property 'Init' are incompatible.
Run Code Online (Sandbox Code Playgroud)

我知道构造函数允许这种行为,但是我不能在这里使用构造函数,因为这些对象被用于内存效率.

我可以在A类中提供另一个Init()定义:

class A {
    Init(param1: number, param2: string): void;
    Init(param1: number) {
        // some code
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,这不太理想,因为现在基类需要知道它的所有派生类.

第三个选项是重命名B类中的Init方法,但这不仅非常丑陋和令人困惑,而是在基类中暴露出Init()方法,这会在基类中导致难以检测的错误错误地调用了Init().

有没有办法实现这种模式,没有上述方法的缺陷?

zlu*_*mer 9

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?
Run Code Online (Sandbox Code Playgroud)

如果您不需要它们可以互换,请修改B的签名以符合A的:

class B extends A {
    Init(param1: number, param2?: string) { // param 2 is optional
        // some more code
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,您可能会发现自己需要创建一个具有完全不同方法签名的类:

class C extends A {
    Init(param1: string) { // param 1 is now string instead of number
        // some more code
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,添加满足当前类和基类调用的方法签名列表。

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,A类就不必知道任何派生类。作为权衡,您需要指定满足基类和子类方法调用的签名列表。