Typescript,准确地表示类方法行为

时间:2015-08-08 08:23:43

标签: javascript typescript

我有几个接口和一个带有可选选项对象的类:

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';

            }
        }
    }
}

我得到的错误:“类A错误地实现了接口IA”。

如果我尝试重载方法:

...
public go(): string;
// Notice the parameter is no longer optional, ? removed.
public go(o: options): string | asObject { /* implementation as above */ }
...

现在我得到:“重载签名与功能实现不兼容”。

我知道我可以删除IA界面上的重载签名并删除A类上的重载方法:

// 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 */ }

让我解释一下:

A类有一个名为go的方法,如果go没有提供选项对​​象,它将返回一个字符串,但如果用户提供了一个选项对象,返回值取决于returnAs字段,表示字符串或对象。

我的问题:

我认为我提供的解决方案并不能准确表示go方法的行为。

有没有办法保留准确的行为以便使用打字稿而不会像我上面描述的前2次尝试那样出错?

当我说出准确的行为时,我的意思是:

我正在寻找一种方法,其中打字稿能够将AObject类型推断为string

var AObject = new A().go();

它可以将AObject推断为stringasObject

var AObject = new A().go({ returnAs: 'object|string' });

我不是百分之百确定在打字稿中是否可行,在这种情况下我会很高兴提出建议。

1 个答案:

答案 0 :(得分:3)

最简单的方法是将A.go结果声明为any

public go(o?: options): any {

或声明功能界面:

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';
            }
        }
    }
}

实际上你甚至不需要声明命名接口:

class A {
    go = <{
        (): string;
        (o: options): string | asObject;
    }>function (o?: options): string | asObject {
    ...

缺点是该函数已添加到A的每个实例中,但您可以将其显式添加到原型中:

class A {
    go: {
        (): string;
        (o: options): string | asObject;
    };
}

A.prototype.go = function (o?: options): any {
...