首页 文章

在TypeScript中扩展Kendo UI窗口

提问于
浏览
1

我正在尝试扩展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' . property '内容'的类型是不相容的 . 类型'(内容?:字符串)=>窗口'不能分配给类型'{():string; (内容?:字符串):窗口; (内容?:JQuery):窗口; }” . “窗口”类型不能指定为“字符串”类型 .

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

1 回答

  • 1

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

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

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

    • 没有参数,返回一个字符串

    • 带有可选的字符串参数,返回Window

    • 带有可选的JQuery参数,返回Window

    's how typescript represents function overloading - it'是在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() 确实需要所有这些重载声明吗?它看起来像实现,采用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'.
    

    因此,重载允许描述参数类型和返回类型之间的关系 . 但是,实现中的编译器不会强制执行该关系 . 如上所述,重载引入的额外复杂性是否值得,值得商榷,如_1309173中所述:

    实际上,JavaScript没有函数重载,一般来说我建议人们根本不使用重载 . 继续使用参数上的联合类型,但如果您有多个不同的行为入口点,或者根据输入而返回不同的返回类型,请使用两个不同的函数!它最终使呼叫者更清楚,更容易编写 .

相关问题