我以明显非界面的方式使用接口。
我有一个程序,它有不同类型的模块,每个模块用一个字符串表示 - 为了参数,我们称它们为"text"
和"image"
。
这些模块类型中的每一种都与多个数据结构相关,我们称之为document
和transient
。因此,对于text
和image
中的每一个,都有一个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
类型的对象。
这一切都很好(即使很难阅读)。我现在要做的是确保在添加新模块类型时(在编译时将其称为table
)tsc
错误,直到我&#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作为值。 DocumentDataMap
和TransientDataMap
继承自此。如果我实际上在真实对象上使用这些接口,这可以正常工作,但由于它们仅用于创建字符串和数据类型之间的关系,扩展 ModuleTypeMap
不会#&# 39;什么都不做。
有没有办法确保接口有某些成员?有没有更好的方法来实现字符串和数据类型/接口之间的关系?我觉得我现在远远超出了TypeScript中接口的预期用途......
答案 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;