具有相同名称但参数数量不同的函数的重载列表语法

时间:2018-02-13 07:11:47

标签: typescript

假设存在一些接口,它有两个相同名称但参数数量不同的函数。

interface IMyInterface<T> {
    someFunction(event: string, callback: (data: T, context: any) => any): this;
    someFunction(callback: (data: T, context: any) => any): this;
}

在TypeScript中,这是一个完全有效的声明,编译得很好。当你试图实现它时,那就是事情变得棘手的时候。

请考虑以下事项:

class MyClassImp<T> implements IMyInterface<T> {

    public someFunction(event: string | undefined, callback: Callback<T>): this {
        return this;
    }

}

对我而言,这是有道理的,因为event作为第一个参数存在,或者它不存在,然后是callback

生成的JavaScript也很有意义:

var MyClassImp = (function () {
    function MyClassImp() {
    }
    MyClassImp.prototype.someFunction = function (event, callback) {
        return this;
    };
    return MyClassImp;
}());

在函数体内部,您可以编写类似event = event || ""if (event) { // do this } else { // do this }的内容。

令人惊讶的是,这无法使用带有此配置的TypeScript编译器(版本2.7.1)进行编译:

{
    "compileOnSave": false,
    "compilerOptions": {
        "noErrorTruncation": true,
        "alwaysStrict": true,
        "module": "commonjs",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "sourceMap": true,
        "strictNullChecks": true,
        "allowJs": false,
        "outDir": "dist",
        "lib": ["es6"],
        "declaration": true,
        "moduleResolution": "node",
        "target": "es5",
        "pretty": true
    },
    "include": [
        "src/**/*"
    ],
    "exclude": [
        "node_modules",
        "test/**/*.spec.ts"
    ]
}

抛出的错误是:

Property 'someFunction' in type 'MyClassImp<T>' is not assignable to the same property in base type 'IMyInterface<T>'.
  Type '(event: string | undefined, callback: Callback<T>) => this' is not assignable to type '{ (event: string, callback: Callback<T>): this; (callback: Callback<T>): this; }'.

为什么无法编译?有人有见识吗?

3 个答案:

答案 0 :(得分:2)

实现签名必须与所有重载声明兼容,并且参数名称与兼容性无关 - 仅考虑参数的类型和顺序。所以第一个参数必须是字符串或回调,第二个参数必须是可选的:

interface IMyInterface<T> {
    someFunction(event: string, callback: (data: T, context: any) => any): this;
    someFunction(callback: (data: T, context: any) => any): this;
}

class MyClassImp<T> implements IMyInterface<T> {

    public someFunction(event: string | ((data: T, context: any) => any), callback?: (data: T, context: any) => any): this {
        return this;
    }

}

此外,如果不同的重载变量返回不同的类型,则必须在类中重复所有重载声明:

interface IMyInterface<T> {
    someFunction(event: string, callback: (data: T, context: any) => any): string;
    someFunction(callback: (data: T, context: any) => any): number;
}

class MyClassImp<T> implements IMyInterface<T> {


  someFunction(event: string, callback: (data: T, context: any) => any): string;
  someFunction(callback: (data: T, context: any) => any): number;
  someFunction(event: string | ((data: T, context: any) => any), callback?: (data: T, context: any) => any): string | number {
                return callback ? '1' : 2;
    }

}

var t = new MyClassImp<string>();

const s = t.someFunction('w', (data, content) => 2); // string

const n = t.someFunction((data, content) => 2); // number

答案 1 :(得分:2)

稍微重新组织代码可以简化事情并修复错误:

type Callback<T> = (data: T, context: any) => any;

interface IMyInterface<T> {
    someFunction(callback: Callback<T>, event: string): this;
    someFunction(callback: Callback<T>): this;
}

class MyClassImp<T> implements IMyInterface<T> {
    someFunction(callback: Callback<T>, event: string): this;
    someFunction(callback: Callback<T>): this;
    someFunction(callback: Callback<T>, event?: string): this {
        return this;
    }
}

注意参数顺序 - 两个重载都需要回调,所以最好先把它放在第一个然后是可选的事件。

您也可以在实现中省略重载(如果您愿意):

class MyClassImp<T> implements IMyInterface<T> {
    someFunction(callback: Callback<T>, event?: string): this {
        return this;
    }
}

答案 2 :(得分:1)

问题是一次callback是第一个参数,另一次是第二个参数,但在你的实现中它始终是第二个参数。

您需要这样的实现签名:

someFunction(eventOrCallback: string | Callback<T>, callback?: Callback<T>): this

如果eventOrCallbackstring,则在方法正文中进行测试。