如何防止TypeScript将字符串文字类型扩展为字符串?
type PropertyName = 'Property1' | 'Property2';
type ObjectWithPropertyName =
{ Property1: string; } |
{ Property2: string; };
const obj1: ObjectWithPropertyName = {
['Property1']: 'works',
}
const prop: PropertyName = 'Property1';
const obj2: ObjectWithPropertyName = {
[prop]: 'works',
}
const func = (prop: PropertyName) => {
const obj: ObjectWithPropertyName = {
[prop]: "fails",
};
};
const funcToo = (prop: PropertyName) => {
const propInner: PropertyName = prop;
const obj: ObjectWithPropertyName = {
[propInner]: "fails",
};
};
在最后一种情况下,错误是这样的:
类型'{[x:string]:string;类型中缺少属性'Property1'; }”,但在“ ObjectWithPropertyName”类型中为必填项。
答案 0 :(得分:2)
它适用于const
示例的原因是打字稿知道prop
只能是'Property1'
。当您处理可以具有任意多个值的参数时,typescript会推断出带有索引签名的类型。
例如,虽然不是特别有用,但它也可以工作,因为prop只能是Property1
:
const func = (prop: 'Property1') => {
const obj: ObjectWithPropertyName = {
[prop]: "fails",
} ;
};
最简单的解决方案是使用类型断言为obj
强制使用所需的类型:
const func = (prop: PropertyName) => {
const obj = {
[prop]: "fails",
} as ObjectWithPropertyName;
};
根据您要尝试执行的操作,您可能会考虑采用其他方法,例如,我们可以捕获返回的Record
传递的实际常量,其中包含该键是什么:
const func = <T extends PropertyName>(prop: T) => {
const obj : Record<T, string> = {
[prop]: "ok",
};
return obj;
};
func('Property1').Property1
答案 1 :(得分:2)
它没有通过导致该问题的函数。
“正常”时有效,是因为编译器仍将prop
的类型缩小为Property1
const prop: PropertyName = 'Property1';
const obj2: ObjectWithPropertyName = {
[prop]: 'works',
}
因为如果添加类型断言'Property1' as PropertyName
,它会因相同的错误而开始失败
const prop: PropertyName = 'Property1' as PropertyName;
const obj2: ObjectWithPropertyName = {
[prop]: 'works',
}
基本上,当prop
的联合类型为'Property1' | 'Property2'
时,值{[prop]: 'something'}
不能分配给{Property1: string}
,也不能分配给{Property2: string}
,这使得不可分配为联合体类型。
您可以通过进行详尽的检查来使其正常工作:
const func = (prop: PropertyName) => {
const obj: ObjectWithPropertyName =
prop === 'Property1' ? { [prop]: "works" } : { [prop]: "works" }
};