I have few interfaces and a class which takes an optional options object:
interface asObject { a: number, b: number }
interface options { returnAs: string; }
interface IA {
go(): string;
go(o: options): string | asObject;
}
class A implements IA {
public go(o?: options): string | asObject {
if(o&& o.returnAs && typeof o.returnAs === 'string') {
switch(o.returnAs) {
case 'object':
return { a: 5, b: 7 };
default:
return 'string';
}
}
}
}
And the error I get: "class A incorrectly implements interface IA".
If I try to overload a method:
...
public go(): string;
// Notice the parameter is no longer optional, ? removed.
public go(o: options): string | asObject { /* implementation as above */ }
...
Now I get: "Overload signature is not compatible with function implementation".
I know I can just remove the overloaded signature on the IA interface and remove the overloaded method on A class:
// Interface IA, notice the parameter is now optional, ? added.
go(o?: options): string | asObject;
// Class A
public go(o?: options): string | asObject { /* implementation as above */ }
Let me explain:
The A class have a method called go, if go won't be provided with options object it will return a string, but if a user provides an options object, the return value depends on the returnAs field, meaning a string or an object.
My question:
I don't think the solution I provided represent accurately the behavior of the go method.
Is there a way to preserve the accurate behavior for the sake of typescript usage and not getting errors as I did with my first 2 tries described above?
When I say accurate behavior I mean:
I'm looking for a way where typescript will be able infer AObject type as string:
var AObject = new A().go();
And it will be able to infer AObject as either string or asObject:
var AObject = new A().go({ returnAs: 'object|string' });
I'm not 100% sure it's possible in typescript, in that kind of case I'd be glad for a suggestion.
The easiest way is to declare A.go result as any:
public go(o?: options): any {
Or declare function interface:
interface asObject { a: number, b: number }
interface options { returnAs: string; }
interface IGoFunction {
(): string;
(o: options): string | asObject;
}
interface IA {
go: IGoFunction;
}
class A implements IA {
go = <IGoFunction>function (o?: options): string | asObject {
if (o && o.returnAs && typeof o.returnAs === 'string') {
switch (o.returnAs) {
case 'object':
return { a: 5, b: 7 };
default:
return 'string';
}
}
}
}
Actually you do not even need to declare named interfaces:
class A {
go = <{
(): string;
(o: options): string | asObject;
}>function (o?: options): string | asObject {
...
Downside is that the function added to each instance of A, but you can explicitly add it to prototype:
class A {
go: {
(): string;
(o: options): string | asObject;
};
}
A.prototype.go = function (o?: options): any {
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With