【问题标题】:Extending Kendo UI Window in TypeScript在 TypeScript 中扩展 Kendo UI 窗口
【发布时间】:2017-05-03 14:27:32
【问题描述】:

我正在尝试扩展 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”。
属性“内容”的类型不兼容。
类型 '(content?: string) => Window' 不可分配给类型 '{ (): string; (内容?:字符串):窗口; (内容?:JQuery):窗口; }'。
类型“窗口”不可分配给类型“字符串”。

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

【问题讨论】:

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


    【解决方案1】:

    如果格式正确,错误消息中的“不可分配给”类型是

    { 
       (): 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 没有函数重载,并且在 一般我建议人们根本不要使用重载。前进 并在参数上使用联合类型,但如果您有多个不同的 行为入口点,或因输入而异的返回类型, 使用两种不同的功能!它最终对呼叫者来说更加清晰,并且 更容易写。

    【讨论】:

    • 所以,如果我理解你的话,我需要在我的类中添加三个重载(没有任何实现),然后为content() 添加一个实现方法?对吗?
    • 是的。我在答案中添加了示例。
    猜你喜欢
    • 1970-01-01
    • 2016-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多