【问题标题】:Extensible Object In Typescript DefinitionTypescript 定义中的可扩展对象
【发布时间】:2015-02-12 19:44:05
【问题描述】:

我有一个可以在 javascript 中扩展的对象类型

var myObject = Library.LibraryType();

myObject.myExtension = MyExtension();

只要扩展遵循某个接口,LibraryType 就可以用它做有用的事情。

但是我如何在打字稿定义文件中表达这一点?我不希望用户一直将所有内容都投射到<any>

我想用字典来做。但是编译器抱怨所有其他成员不遵守字典定义。

export interface IExtension {
}
export interface IExtensibleLibraryType {
    something: string;
    otherthing: (args: number) => void;

    [ keyOfExtension: string ]: IExtension;
}

它说所有其他成员都不是IExtension

我原以为编译器会强制字典成员作为字典mytype['keyOfExtension'] 访问,而所有其他成员都可以使用. 表示法访问?为什么这不是一件事?

有没有办法解决这个问题? 或者我只需要告诉大家一直投到any吗? 或者强制用户在自己的代码中扩展接口(最好的选择,但我敢打赌人们更有可能这样做)?

如果.d.ts 能够像对文档的有用补充一样完整地描述库的 API,我真的很高兴。

【问题讨论】:

    标签: module typescript definition typescript1.4


    【解决方案1】:

    TypeScript 目前对经典 OO 的支持比您使用的方法更好。

    class LibraryType {
        constructor() {
            // equivalent of your Library.LibraryType() function
        }
    
    }
    
    class MyExtendedVersion extends LibraryType {
        extension: blah
    }
    

    遗憾的是,这需要您更改库的工作方式。您必须导出一个类,而不是导出工厂函数。在内部,你的类的代码必须使用this 来访问它自己的实例数据。

    在将自己的大型项目迁移到 TS 时,我尝试了几个文件的经典转换并很快放弃了它。这是一种“重写”的体验,这很糟糕,因为我需要在之前的版本中进行错误修复并将它们合并到 TS 版本中。如果您所要做的只是在这里和那里添加一些类型注释,那么迁移到 TS 会容易得多。所以我使用接口、$.extend 和强制转换(类型断言)来避免重写。

    有一个request for a language feature here 可能会在未来帮助我们,但目前还没有在路线图上。

    【讨论】:

      【解决方案2】:

      它说所有其他成员都不是IExtension。

      编译器在这里为您提供帮助。如果您说字符串访问的任何内容都应该是IExtension 类型,那么您自己的成员(例如something)需要符合允许foo['something']

      修复:

      extensions 下移一级:

      interface IExtension {
          foo:string;
      }
      interface IExtensibleLibraryType {
          something: string;
          extensions: {[ keyOfExtension: string ]: IExtension};
      }
      
      function getLib():IExtensibleLibraryType{
          return {
              something:'',
              extensions: {}
          };
      }
      
      
      var test = getLib();
      test.extensions['good'] = {foo:'test'};
      test.extensions['bad'] = {foos:'test'}; // Error 
      

      【讨论】:

        【解决方案3】:

        对我来说,定义“特定类型 A 加上额外的东西”类型的对象的最简单方法是这样的:

        interface A {
          /* Whatever needed as a base */
        }
        
        type AExtended = {
          [K in keyof A]: A[K];
          extraField: string;
        }
        

        所以,基本上你定义的是一个AExtended 类型,除了来自A 的所有属性之外,让我们定义你自己的。

        [K in keyof A]: A[K];
        

        Mapped type A 中的每个键K 的类型都与A[K] 完全相同,并且因为K 保证是A 中的键,所以这些类型将永远平等。

        【讨论】:

          猜你喜欢
          • 2014-12-09
          • 1970-01-01
          • 2019-04-08
          • 2016-05-16
          • 1970-01-01
          • 2020-08-11
          • 2016-05-06
          • 2015-11-05
          • 2016-09-19
          相关资源
          最近更新 更多