我正在尝试扩展Telerik的Kendo UI类之一Window
小部件。我使用的是TypeScript 2.2.2。
供您参考,这就是Window
的定义。我只包括与此问题相关的部分。
class Window extends kendo.ui.Widget {
static extend(proto: Object): Window;
constructor(element: Element, options?: WindowOptions);
content(): string;
content(content?: string): kendo.ui.Window;
content(content?: JQuery): kendo.ui.Window;
}
我想覆盖content(string)
方法。我使用this example作为我的代码的基础。所以我有以下内容:
export class AngularizedWindow extends kendo.ui.Window {
constructor(element: Element, options?: kendo.ui.WindowOptions) {
super(element, options);
}
content(content?: string) : kendo.ui.Window {
console.log("Setting content");
return super.content(content);
}
}
然而,它给了我这个错误:
ts \ widgets \ AngularizedWindow.ts(2,18):错误TS2415:类'AngularizedWindow'错误地扩展了基类'Window'。
财产“内容”的类型是不相容的 输入'(内容?:字符串)=> Window'不能赋值为'{():string; (内容?:字符串):窗口; (内容?:JQuery):窗口; }”。
类型'Window'不能分配给'string'类型。
我做错了什么?我不明白如何解释这个错误。
答案 0 :(得分:1)
"不能分配给"在格式正确时键入错误消息是
{
(): string;
(content?: string): Window;
(content?: JQuery): Window;
}
这是一个有3个所谓的callable signatures的类型,它描述了可以通过以下三种方式之一调用的内容:
这就是打字稿代表函数重载的方式 - 它是在剑道content
中声明的Window
的实际类型,因为它有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()
确实需要所有这些重载声明吗?它看起来像实现,采用union类型并返回union类型,足以处理所有用例。
但是,没有重载,此代码无法编译:
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没有函数重载和 一般我建议人们根本不使用超载。前进 并在参数上使用union类型,但如果你有多个不同的 行为切入点,或基于输入而不同的返回类型, 使用两个不同的功能!它最终会让来电者更清楚 你写起来比较容易。