如果格式正确,错误消息中的“不可分配给”类型是
{
(): string;
(content?: string): Window;
(content?: JQuery): Window;
}
这是一个有 3 个所谓的 callable signatures 的类型,它描述了可以通过 3 种方式之一调用的东西:
- 不带参数,返回字符串
- 带有可选字符串参数,返回窗口
- 带有可选的 JQuery 参数,返回窗口
这就是 typescript 表示函数重载的方式 - 它是 kendo Window 中声明的 content 的实际类型,因为它有 3 个重载变体:
content(): string;
content(content?: string): kendo.ui.Window;
content(content?: JQuery): kendo.ui.Window;
Javascript 没有函数重载,因此 typescript 会尽可能地模拟它,并且当您使用重载方法时它会起作用。
但是,当您实现(或覆盖)重载方法时,打字稿无济于事。你只能有一个实现,它必须在运行时处理所有可能的参数组合。因此,您的扩展类必须重复 content() 的所有重载声明并提供一种实现,与所有声明的变体兼容并能够处理所有变体,如下面的示例所述:https://www.typescriptlang.org/docs/handbook/functions.html#overloads
我没有使用 Kendo UI 的经验,所以我只是根据使用 typescript 2.3 编译并在 node.js 中运行的代码编写了一个最小的示例:
base.ts
export class Widget {}
export class Element {}
export class WindowOptions {}
export class JQuery {}
export namespace kendo {
export namespace ui {
export class Window extends Widget {
static extend(proto: Object): Window {return null}
constructor(element: Element, options?: WindowOptions) { super() }
content(): string;
content(content?: string): Window;
content(content?: JQuery): Window;
content(content?: string | JQuery): Window | string {
return null;
}
}
}
}
d.ts
import { WindowOptions, JQuery, kendo } from './base';
export class AngularizedWindow extends kendo.ui.Window {
constructor(element: Element, options?: WindowOptions) {
super(element, options);
}
content(): string;
content(content?: string): kendo.ui.Window;
content(content?: JQuery): kendo.ui.Window;
content(content?: string | JQuery) : kendo.ui.Window | string {
if (typeof content === 'undefined') {
console.log('implementation 1');
return super.content();
} if (typeof content === 'string') {
console.log('implementation 2');
return super.content(content);
} else { // ought to be jQuery
console.log('implementation 3');
return super.content(content);
}
}
}
let a = new AngularizedWindow(null);
a.content();
a.content('b');
a.content({});
编译运行
./node_modules/.bin/tsc base.ts d.ts
node d.js
打印出来
implementation 1
implementation 2
implementation 3
现在,当您查看示例代码时,会引出一个问题:content() 真的需要所有这些重载声明吗?看起来,采用联合类型并返回联合类型的实现足以处理所有用例。
但是,如果没有重载,这段代码无法编译:
let s: string = a.content();
错误:
d.ts(32,5): error TS2322: Type 'string | Window' is not assignable to type 'string'.
Type 'Window' is not assignable to type 'string'.
因此,重载允许描述参数类型和返回类型之间的关系。但是,编译器在实现中不会强制执行这种关系。正如this comment by one of typescript developers 所表达的那样,重载带来的额外复杂性是否值得值得商榷:
实际上,JavaScript 没有函数重载,并且在
一般我建议人们根本不要使用重载。前进
并在参数上使用联合类型,但如果您有多个不同的
行为入口点,或因输入而异的返回类型,
使用两种不同的功能!它最终对呼叫者来说更加清晰,并且
更容易写。