我有一个通用接口(interface),其中我希望一个属性只包含来自另一个属性的键,并且具有相同的类型....
interface IMyInterface<T> {
propA: T;
propB: { [key in keyof T]?: T[key] };
}
这很好,我以前做过很多次类似的事情......基本上我希望它根据我传递给 propA 的内容推断 T 是什么。
但是这是我的问题,我有一本包含许多 IMyInterface 类型的字典....
interface IMyDictionary {
[key: string]: IMyInterface;
}
这就是我的问题所在,上面的定义需要一个泛型类型....但是我使用的任何类型都将应用于每个属性。如果我使用 any 而不是它会破坏这一点,因为在声明我的字典时它假定一切都是 any。
interface IInterfaceA {
name: string;
age: number;
}
const objA: IInterfaceA = {
name: 'John',
age: 18
}
const myDictionary: IMyDictionary {
test1: {
propA: objA,
propB: { age: 40 }
}
}
所以基本上,当将值分配给上面的 myDictionary 时,我希望它推断 propA 是 IInterfaceA 类型,并且在 propB 中只允许属性名称为字符串类型和年龄为数字类型。
我可以通过不定义 IMyDictionary 类型,一个一个地创建每个项目,然后将它们分配给一个新对象 (myDictionary) 来轻松地做到这一点......
const test1: IMyInterface = {
propA: objA,
propB: { age: 40 }
}
const myDictionary = { test1 }
这会推断出 test1 的通用类型,然后推断出 myDictionary 的类型,使用准确的属性名称,而不是字符串数组。但如果可能的话,我宁愿使用普通的旧对象赋值语法。
我想不出一种方法来声明 IMyDictionary 的类型以强制它为 IMyInterface 的每个实例推断通用类型。或者,我对定义 IMyInterface 以推断 propB 的属性和类型的不同方法的想法持开放态度。
提前致谢!
最佳答案
您要查找的类型是字典,其中每个条目都是一些 IMyInterface<T>
类型,但不是任何特定 T
.这可能最好表示为 existential type喜欢(可能){[k: string]: IMyInterface<exists T>}
,目前在 TypeScript 中不受本地支持(大多数其他具有泛型的语言也不支持)。 TypeScript(以及大多数其他具有泛型的语言)只有通用类型:想要类型值的人 X<T>
可以为 T
指定任何类型他们想要的,并且值(value)的提供者必须能够遵守。存在类型则相反:想要提供类型值的人 X<exists T>
可以为 T
选择任何特定类型他们想要的,并且该值的接收者只需要遵守。存在类型让您可以将泛型类型“隐藏”在非泛型类型中。
但是,TypeScript 没有存在类型,所以我们必须做些别的事情。 (好吧,它没有原生存在类型。您可以通过使用通用函数和通过回调反转控制来 emulate them,但这比我要建议的解决方案更复杂接下来。如果你仍然对存在主义感兴趣,你可以阅读关于它的链接文章)
我们能做的下一个最好的事情是描述 IMyDictionary
的形状作为泛型类型,我们并不真正关心它,并让编译器尽可能地为我们推断它。这是一种方法:
type IMyDictionary<T> = { [K in keyof T]: IMyInterface<T[K]> }
const asIMyDictionary = <T>(d: IMyDictionary<T>) => d;
这个想法是,而不是将变量声明为 IMyDictionary
类型, 你使用辅助函数 asIMyDictionary()
取值并生成合适的类型 IMyDictionary<T>
.顺便说一句,这只有效,因为类型 IMyDictionary<T>
是 homomorphic mapped type , 所以 T
可以从 IMyDictionary<T>
类型的值中推断出来.让我们看看它的实际效果:
const myDictionary = asIMyDictionary({
test1: {
propA: { name: "John", age: 18 },
propB: { age: 40 }
},
test2: {
propA: { size: 10, color: "blue" },
propB: { color: "purple" }
},
test3: {
propA: { problem: true },
propB: { oops: false } // error!
// ~~~~~~~~~~~~
// 'oops' does not exist in type '{ problem?: boolean | undefined; }'
}
});
这有效,并在您预期的地方出现错误。耶!
这里的警告是你仍然需要绕过这个 T
你不关心的类型。您希望只处理具体的 IMyDictionary
的任何函数或类型将不得不变得通用。也许这对你来说并不太痛苦。如果是,您可以考虑“模拟”存在类型。但我已经在这里写了很多,所以希望上面的内容能帮助你......如果你需要我写出模拟的存在版本,我可以。
祝你好运!
关于typescript - 在字典属性中推断通用类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56079590/