【问题标题】:Require members in interface需要接口中的成员
【发布时间】:2018-02-02 18:26:15
【问题描述】:

我以一种明显的非接口方式使用接口。

我有一个程序,它有不同类型的模块,每个模块都用一个字符串表示——为了论证,我们称它们为"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 在编译时出错,直到我添加了一个"table" 条目到DocumentDataMapTransientDataMap.

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

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 不会做任何事情。

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

【问题讨论】:

  • AllData会报错,所以在使用上会报错,在声明时很难报错
  • @TitianCernicova-Dragomir 您所说的用法是指运行时吗?因为 TypeScript 会将所有这些编译成 function getAllData(moduleType) { }。无论哪种方式,我都没有看到任何编译 运行时错误。
  • 我在 ts 2.7 的 trn: TransientDataMap[T]; 上收到此错误 Type 'T' cannot be used to index type 'TransientDataMap'

标签: typescript inheritance interface


【解决方案1】:

没有办法强制接口拥有成员。如果接口在某些方面不符合要求,您将收到有关接口使用的错误。在您的示例中,如果 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;

【讨论】:

  • 仍然没有看到错误(我在 TypeScript 2.6.2 上),但虚拟分配将起作用。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-17
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2013-01-03
  • 1970-01-01
  • 2011-11-10
相关资源
最近更新 更多