当定义需要import语句时,如何扩展现有接口?

时间:2016-08-05 09:46:50

标签: typescript

我已经创建了一个自定义Knockout扩展程序,但我在扩展Knockout定义文件提供的现有界面时遇到了问题。

增量剂/ Numeric.ts

var i=0;

Boot.ts

import * as ko from "knockout";

function Extender(target: KnockoutObservable<number>, options: IOptions = {}): KnockoutObservable<number> {
    // ...
};

interface IOptions {
    // ...
}

export {Extender as NumericExtender, IOptions as INumericExtenderOptions}

为了让编译器了解import * as ko from "knockout"; import {NumericExtender} from "./Extenders/Numeric"; class Boot { public constructor() { ko.extenders.numeric = NumericExtender; } } ,我需要扩展现有的接口:

ko.extenders.numeric

现在我遇到了麻烦。要访问interface KnockoutExtenders { numeric(target: KnockoutObservable<number>, options?: INumericExtenderOptions): KnockoutObservable<number>; } ,我需要INumericExtenderOptions声明:

import

但是当添加import语句时,该文件被视为一个模块which makes it impossible to extend an existing interface

有没有办法做到这一点,还是我需要将import {INumericExtenderOptions} from "./Extenders/Numeric"; 移到定义文件中以避免IOptions

1 个答案:

答案 0 :(得分:2)

好像您正在使用全局版本的淘汰声明文件。我认为不可能在模块声明文件中扩展全局范围中定义的接口。有几种解决方案:

  • 我认为最简单的解决方案是将您的界面置于全局命名空间。对于IOptions,这变为:

    // index.d.ts
    interface IOptions {
      // ¯\_(ツ)_/¯
    }
    
    interface KnockoutExtenders {
      numeric(target: KnockoutObservable<number>, options?: IOptions): KnockoutObservable<number>;
    }
    

    现在您可以在任何地方使用数字函数访问IOptions和KnockoutExtenders,因为声明文件仍然是全局的。

  • 另一种解决方案是拉入模块版本(我认为这是我首选的解决方案,因为你没有用所有的淘汰类型污染全局命名空间)。在淘汰的情况下:typings install --save knockout。然后,您必须在需要时专门导入所需的类型。例如。你的数字变成了

    // src/numeric.ts
    import { Observable } from "knockout"
    
    export function Extender(target: Observable<number>, options: IOptions = {}): Observable<number> {
      // ¯\_(ツ)_/¯
    };
    
    export interface IOptions {
      // ¯\_(ツ)_/¯
    }
    

    然后你可以在另一个声明文件中扩充淘汰赛模块。例如:

    // index.d.ts
    import { Observable } from "knockout"
    import { IOptions } from './src/numeric'
    
    declare module "knockout" {
      interface Extenders {
        numeric(target: Observable<number>, options?: IOptions): Observable<number>
      }
    }
    

    然后,您应该可以在应用程序的任何位置使用增强的扩展器界面:

    // src/boot.js
    import { extenders } from "knockout"
    import { Extender } from "./numeric"
    
    class Boot {
      public constructor() {
        extenders.numeric = Extender
      }
    }
    
  • 最终的解决方案,可能是最好地解决您的问题,是使用模块化声明文件,但扩充全局模块。您的numeric.ts保持不变,您的声明文件变为:

    import { IOptions } from './src/numeric'
    
    declare global {
      interface KnockoutExtenders {
        numeric(target: KnockoutObservable<number>, options?: IOptions): KnockoutObservable<number>
      }
    }
    

有关详细信息,请查看page on declaration merging from the typescript handbook.