请考虑以下类型:
type RequestSpecification = {
type: "get" | "post";
parameters: { [key: string]: ParameterSpecification }
};
type ParameterSpecification = {
required: boolean;
// ...
}
现在,它可以像这样创建变量:
const requestSpecification: RequestSpecification = {
type: "get",
parameters: {
id: {
required: true
},
nickname: {
required: false
}
}
}
我们不能调用requestSpecification.parameters
的现有属性:
// no error!!!
console.log(requestSpecification.parameters.asdf);
我希望TypeScript知道id
中只有nickname
和parameters
可用。
如何通过泛型解决?
答案 0 :(得分:2)
您使用的字符串索引类型告诉TypeScript parameters
可以具有字符串的任何属性。换句话说,'asdf'
(以及任何其他字符串)被允许作为属性。不允许将数字作为属性。由于这是您声明的类型,因此TypeScript的行为符合预期,因为它允许'asdf'
作为parameters
的属性。
这是关于字符串索引类型的常见混淆,可能会导致您在TypeScript生涯中一遍又一遍地感到惊讶。
缩小类型的一种方法是to use a generic like this。在下面的示例中,我们说P
扩展了字符串。结果,parameters
仍然受限于字符串属性。实例化类型时,我们传入的是'id' | 'nickname'
的字符串并集。这就告诉编译器确切地允许使用两个字符串。
type RequestSpecification<P extends string> = {
type: "get" | "post";
parameters: { [K in P]: ParameterSpecification }
};
type ParameterSpecification = {
required: boolean;
}
const requestSpecification: RequestSpecification<'id' | 'nickname'> = {
type: "get",
parameters: {
id: {
required: true
},
nickname: {
required: false
}
}
}
// This will now be a compiler error. Hooray!
console.log(requestSpecification.parameters.asdf);