在TypeScript中扩展Kendo UI窗口

时间:2017-05-03 14:27:32

标签: typescript kendo-ui typescript2.0 kendo-window

我正在尝试扩展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'类型。

我做错了什么?我不明白如何解释这个错误。

1 个答案:

答案 0 :(得分:1)

"不能分配给"在格式正确时键入错误消息是

{ 
   (): string; 
   (content?: string): Window; 
   (content?: JQuery): Window; 
}

这是一个有3个所谓的callable signatures的类型,它描述了可以通过以下三种方式之一调用的内容:

  • 不带参数,返回一个字符串
  • 带有可选的字符串参数,返回Window
  • 带有可选的JQuery参数,返回Window

这就是打字稿代表函数重载的方式 - 它是在剑道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类型,但如果你有多个不同的   行为切入点,或基于输入而不同的返回类型,   使用两个不同的功能!它最终会让来电者更清楚   你写起来比较容易。