【问题标题】:How to extend an interface declared in an external library d.ts?如何扩展在外部库 d.ts 中声明的接口?
【发布时间】:2016-10-04 13:37:20
【问题描述】:

我使用这样的记录方法安装了knockout 定义。

npm install @types/knockout

效果很好,我可以像这样在任何地方导入它。

import * as ko from "knockout";

但是,我坚持使用一些自定义内容扩展 KnockoutStatic 接口。我正在尝试迁移基于 <reference ... />namespace 的大型 TS 应用程序以使用模块。之前,我轻松地声明了扩展接口 anywhere 并且声明被合并了。假设我的扩展程序看起来像这样。

interface KnockoutStatic {
  doSomething(): void;
}

我尝试创建一个 KnockoutExtensions.d.ts 文件,并在其中声明它是这样的。

import "knockout";

declare module "knockout" {
  export interface KnockoutStatic {
    doSomething(): void;
  }
}

但是当我在某处同时导入knockout 和我的扩展时,TS 仍然无法解析doSomething 调用。

import * as ko from "knockout";
import "./KnockoutExtensions";

ko.doSomething(); // error

使用 TypeScript 2.0 和新的d.ts 子系统扩展库接口的正确方法是什么?

我正在使用安装了 TypeScript 2.0 的 Visual Studio 2015 Update 3。

【问题讨论】:

    标签: typescript typescript2.0


    【解决方案1】:

    我发现winston 有同样的问题,使用export = 语法。当它显示 react 做了同样的事情时,我发现此页面很有帮助:https://www.credera.com/blog/technology-solutions/typescript-adding-custom-type-definitions-for-existing-libraries/

    他们推荐的解决方案是这样的:

    import 'react';
    
    declare module 'react' {
        interface OlHTMLAttributes<T> {
            type?: "1" | "a" | "A" | "i" | "I";
        }
    }
    

    只需导入模块,然后声明它允许此声明块中的任何接口扩展现有的接口,并且在代码的其他部分中,您可以像往常一样继续使用该接口;即你仍然会导入 reactwinstonknockout 并且你会看到这些新的接口成员。您不必开始引用自定义界面或类似的东西。

    【讨论】:

      【解决方案2】:

      您可以轻松扩展“淘汰赛”或任何其他 TypeScript 命名空间。

      示例:创建 knockout-extension.d.ts 文件

      /// <reference path="<path-to-typings-dir>/knockout/index.d.ts" />
      
      declare module 'knockout' {
      
        export interface CustomType {
      
          customField: string;
      
          customMethod(arg1: number, arg2: boolean): boolean;
        }
      
        namespace customNamespace {
      
          export interface AnotherCustomType {
            customField1: string;
            customField2: boolean;
          }
        }
      
        // NOTE: extending existing interface
        export interface KnockoutStatic {
          customMethod(): void;
        }
      }
      

      注意:确保该文件被 TypeScript 编译器拾取。

      使用扩展模块中新定义的类型。

      // one way
      import { CustomType } from 'knockout';
      
      const foo: CustomType;
      
      // second way
      import * as kc from 'knockout';
      
      const foo: kc.CustomType;
      const bar: kc.customNamespace.AnotherCustomType;
      

      有关模块和命名空间的更多信息,您可以查看 ModulesNamespaces 上的 TypeScript 文档并使用它们 together

      干杯!

      【讨论】:

      • 非常感谢!!!
      【解决方案3】:

      问题是knockout 键入文件使用export = 语法,它不是“增强友好”。请参阅this 作为参考。

      对我来说最简单的解决方案是将扩展包在 declare global { } 中,因为 knockout 键入文件声明了全局范围内的所有内容。

      declare global {
        interface KnockoutStatic {
          doSomething(): void;
        }
      }
      

      【讨论】:

        【解决方案4】:

        此代码适用于我

        // observable.ts
        export class Observable<T> {
          // ... implementation left as an exercise for the reader ...
        }
        
        // map.ts
        import { Observable } from "./observable";
        declare module "./observable" {
          interface Observable<T> {
            map<U>(f: (x: T) => U): Observable<U>;
          }
        }
        Observable.prototype.map = function (f) {
          // ... another exercise for the reader
        };
        
        // consumer.ts
        import { Observable } from "./observable";
        import "./map";
        let o: Observable<number>;
        o.map((x) => x.toFixed());
        

        【讨论】:

          【解决方案5】:

          我试图扩展 Express Request 对象,以便可以使用 req.log.info 记录一些内容。以下设置适用于我

          // tsconfig.json
          {
            "compilerOptions": {
              ...,
              "baseUrl": ".",
              "paths": {
                "*": ["node_modules/*", "types/*"]
              }
            },
            "include": ["src/**/*"],
            "files": ["./types/express-extension.d.ts"],
            "ts-node": {
              "files": true
            }
          }
          
          // types/express-extension.d.ts
          import 'express';
          
          declare module 'express' {
            export interface Request {
              log?: {
                debug: (str: string) => void,
                info: (str: string) => void,
                warn: (str: string) => void,
                error: (str: string) => void,
              }
            }
          }
          

          我的文件结构如下:

          src
          |_ ...
          types
          |_ express-extension.d.ts
          tsconfig.json
          package.json
          

          【讨论】:

            【解决方案6】:

            您需要在模块之外创建界面。 不要用 export 声明它。

            module example  {
               //...do stuff
            }
             
            interface KnockoutStatic {
              doSomething(): void;
            }
            

            您可以将其添加到单独的文件中,例如添加界面扩展以保持干净。

            【讨论】:

            • 这不起作用,这仅在我不使用模块,而是使用纯命名空间时才起作用。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-05-25
            • 1970-01-01
            • 1970-01-01
            • 2016-01-02
            • 1970-01-01
            • 2021-06-18
            相关资源
            最近更新 更多