Reputation: 4102
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.
Upvotes: 3
Views: 191
Reputation: 1870
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 {
...
Upvotes: 3