需要界面

时间:2018-02-02 18:26:16

标签: typescript inheritance interface

我以明显非界面的方式使用接口。

我有一个程序,它有不同类型的模块,每个模块用一个字符串表示 - 为了参数,我们称它们为"text""image"

这些模块类型中的每一种都与多个数据结构相关,我们称之为documenttransient。因此,对于textimage中的每一个,都有一个document数据接口和一个transient数据接口。

我使用奇怪的中间件接口形成这些类型和数据结构之间的关系:

type ModuleType = "image" | "text";

interface TextDocumentData { /* ... */}
interface ImageDocumentData { /* ... */}

interface DocumentDataMap {
    "image": ImageDocumentData;
    "text": TextDocumentData;
}

interface TextTransientData { /* ... */}
interface ImageTransientData { /* ... */}

interface TransientDataMap {
    "image": ImageTransientData;
    "text": TextTransientData;
}

然后我将其用于如下函数:

interface AllData<T extends ModuleType> {
    doc: DocumentDataMap[T];
    trn: TransientDataMap[T];
}

function getAllData<T extends ModuleType>(moduleType: T): AllData<T> { /* ... */ }

这将使getAllData("text").doc;返回TextDocumentData类型的对象。

这一切都很好(即使很难阅读)。我现在要做的是确保在添加新模块类型时(在编译时将其称为tabletsc错误,直到我&#39;我在"table"DocumentDataMap添加了TransientDataMap条目。

这是我迄今为止所尝试过的:

type ModuleType = "image" | "text" | "table";
type DocumentData = TextDocumentData | ImageDocumentData | TableDocumentData;
type TransientData = TextTransientData | ImageTransientData;

type ModuleTypeMap<T> = {[m in ModuleType]: T};

interface TextDocumentData { /* ... */}
interface ImageDocumentData { /* ... */}
interface TableDocumentData { /* ... */}

interface DocumentDataMap extends ModuleTypeMap<DocumentData> {
    "image": ImageDocumentData;
    "text": TextDocumentData;
    "table": TableDocumentData;
}

interface TextTransientData { /* ... */}
interface ImageTransientData { /* ... */}

// This should cause an error (there's no entry for tables!)
interface TransientDataMap extends ModuleTypeMap<TransientData> {
    "image": ImageTransientData;
    "text": TextTransientData;
}

类型ModuleTypeMap强制使用每个可能的ModuleType作为键的对象,并键入T作为值。 DocumentDataMapTransientDataMap继承自此。如果我实际上在真实对象上使用这些接口,这可以正常工作,但由于它们仅用于创建字符串和数据类型之间的关系,扩展 ModuleTypeMap不会#&# 39;什么都不做。

有没有办法确保接口有某些成员?有没有更好的方法来实现字符串和数据类型/接口之间的关系?我觉得我现在远远超出了TypeScript中接口的预期用途......

1 个答案:

答案 0 :(得分:0)

无法强制接口拥有成员。如果接口的使用不符合某种方式,您将收到有关接口使用的错误。在您的示例中,如果table未定义,则会出现错误,它只是在AllData接口中,并且它不是一个非常易读的错误。

根据对您的重要程度,您可以采取一些措施来确保在声明网站附近出现清晰的错误:

添加虚拟变量分配

interface TransientDataMap {
    "image": ImageTransientData;
    "text": TextTransientData;
}
// If you get an error typescript here check the interface above
let transientDataMapGuard : {[m in ModuleType]: any } = <TransientDataMap> {};

在定义界面时使用辅助函数

// Dummy type helper
function extendsModule<I extends  { [m in ModuleType]: any }>(): I{
    return null as any;
}
// This will cause an error if you don't have all the memebers
let transientDataMapDeclarationHelper =  (extendsModule<{
    "image": ImageTransientData;
    "text": TextTransientData;
}>());

type TransientDataMap = typeof transientDataMapDeclarationHelper;