问题
How can I achieve something similar to this pattern in typescript?
class A {
Init(param1: number) {
// some code
}
}
class B extends A {
Init(param1: number, param2: string) {
// some more code
}
}
The code snipped above appears like it should work, however on close inspection of How Typescript function overloading works it makes sense that an error is thrown:
TS2415: 'Class 'B' incorrectly extends base class 'A'.
Types of property 'Init' are incompatible.
I know that constructor functions allow this behaviour, but I can't use constructors here as these objects are pooled for memory efficiency.
I could provide another definition of Init() in class A:
class A {
Init(param1: number, param2: string): void;
Init(param1: number) {
// some code
}
}
However this is less than ideal as now the base class needs to know about all of its derived classes.
A third option would be to rename the Init method in class B but that would not only be pretty ugly and confusing, but leave exposed the Init() method in the base class, which would cause difficult-to-detect bugs when the base class Init() is called by mistake.
Is there any way to implement this pattern that doesn't have the pitfalls of the aforementioned approaches?
回答1:
TypeScript complains about methods not being interchangeable: what would happen if you do the following?
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?
If you don't need them to be interchangeable, modify B's signature to comply with A's:
class B extends A {
Init(param1: number, param2?: string) { // param 2 is optional
// some more code
}
}
However, you might find yourself in a situation where you need to create a class with totally different method signature:
class C extends A {
Init(param1: string) { // param 1 is now string instead of number
// some more code
}
}
In this case, add a list of method signatures that satisfy both current class and base class calls.
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
}
}
}
That way the A class doesn't have to know about any of the derived classes. As a trade-off, you need to specify a list of signatures that satisfies both base class and sub class method calls.
来源:https://stackoverflow.com/questions/38025364/typescript-child-class-function-overloading