Typescript 定义中的可扩展对象

Extensible Object In Typescript Definition

我有一个可以在 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,就像对文档的有用补充,我真的很喜欢。

It says all the other members are not 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 

TypeScript 目前对 classical OO 的支持比对您正在使用的方法更好。

class LibraryType {
    constructor() {
        // equivalent of your Library.LibraryType() function
    }

}

class MyExtendedVersion extends LibraryType {
    extension: blah
}

遗憾的是,这需要您更改图书馆的工作方式。您必须导出 class,而不是导出工厂函数。在内部,您的 class 的代码将不得不使用 this 来访问它自己的实例数据。

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

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

对我来说,定义“特定类型 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 开始,这些类型将始终相等。