假设存在一些接口,它有两个相同名称但参数数量不同的函数。
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; }'.
为什么无法编译?有人有见识吗?
答案 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
如果eventOrCallback
是string
,则在方法正文中进行测试。