我看到这样的用例是,您希望 GenericTypes 将任何类型的字符串作为键,但仍想在您声明它们时准确确定这些键的值。
在这种情况下,您可以使用Record 类型将Obj1 的允许键限制为您指定的键。
type GenericType<K extends string> = Record<K, {
prop1: string,
prop2?: string,
prop3?: number,
}>
然后在定义Obj1时,您可以通过将允许键的并集设置为第一个类型参数来指定允许的键应该是什么。
const Obj1: GenericType<"key1" | "key2"> = {
key1: {
prop1: "hi",
},
key2: {
prop1: "bye",
prop2: "sup",
},
};
TypeScript 现在可以让您访问 key1 和 key2 并且具有完全的类型安全性。
Obj1.key1
// (property) key1: {
// prop1: string;
// prop2?: string | undefined;
// prop3?: number | undefined;
// }
编辑
根据 OP 的评论,听起来他宁愿不指定所有键名,也不愿手动检查可选字段是否存在。
在确保您声明的对象与GenericType 接口的约束匹配的同时,我能想到的最佳方法是执行以下操作。
首先你需要这个工具类型:
type Constraint<T> = T extends Record<string, {
prop1: string,
prop2?: string,
prop3?: number,
}> ? T : never
如果T 不匹配约束,这将返回never,否则只返回T。
现在你声明你真正想要的普通对象。没有类型注释。
const CorrectObj = {
key1: {
prop1: "hi",
},
key2: {
prop1: "bye",
prop2: "sup",
},
};
然后将此对象字面量分配给另一个变量,但声明新变量的类型必须为Constraint<typeof CorrectObj>
const CheckedObj: Constraint<typeof CorrectObj> = CorrectObj
如果CorrectObj 与约束匹配,则CheckedObj 将是CorrectObj 的简单副本,其中包含所有可用字段。
如果对象字面量与约束不匹配,但是在尝试将 CheckedBadObj 分配给字面量时会出现类型错误:
const BadObj = {
key1: {
progfdgp1: "hi",
},
key2: {
prop1: "bye",
prdfgop2: "sup",
},
};
const CheckedBadObj: Constraint<typeof BadObj> = BadObj
// ^^^^^^^^^^^^^
// Type '{ key1: { progfdgp1: string; }; key2: { prop1: string; prdfgop2: string; }; }' is not assignable to type 'never'. (2322)
解释是Constraint<T>当T不匹配时是never,但你仍然试图将非never值分配给CheckedBadObj,导致类型冲突!
这涉及到在声明每个对象字面量的两个实例时有点重复,但这是唯一的方法
- 让 TypeScript 知道确切对象上存在哪些字段,包括所有子对象,同时仍然
- 检查“通用”类型的值
匹配您的约束
您可以在playground 中尝试这种方法。