假设我有一个对象,其某些属性的类型并不完全相同,并且我想为动态标识的属性分配一个动态值。这在JavaScript中工作得很好,但我如何在TypeScript中做到这一点,消除not assignable to type 'never'
TS(2322(错误,理想情况下不使用any
?
示例代码(此处为操场(:
interface Film {
name : string;
durationInSeconds : number;
}
const myFunction = function(
film: Film,
filmPropertyName: keyof Film,
newValue: string | number
) {
let value = film[filmPropertyName];
console.log('Existing value:', value); //value is of type `string | number`, inferred in prior line
//That means that on read, film[filmPropertyName] is of type `string | number` as expected.
//However, on write, it's of type `never.`
film[filmPropertyName] = newValue; //not assignable to type 'never'.ts(2322)
value = newValue; //works just fine with both sides as `string | number`
//Checking that types match seems like a sensible requirement but doesn't help:
if(typeof film[filmPropertyName] === typeof newValue) {
value = newValue; //works fine
film[filmPropertyName] = newValue; //same error as above
}
//even checking that both are a specific standard type doesn't help:
if(typeof film[filmPropertyName] === 'string' && typeof newValue === 'string') {
value = newValue; //works fine
film[filmPropertyName] = newValue; //same error as above
}
}
在这个小例子中,可以建议移除类型混合,例如通过将durationInSeconds
设置为string
类型并仅将newValue
参数的类型更改为string
。虽然在这样的一个小例子中这可能是可以的,但在需要其他类型的更复杂的真实代码中它不起作用。
对于遇到此问题的其他人,将film
参数的类型更改为any
可以满足此错误,但可能会触发其他错误,例如,如果film
或其属性在本函数主体期间传递给其他函数。
在赋值之前进行强制转换,例如(film as any)[filmPropertyName] = newValue
,会使错误消失,并且可能至少应该在第一个类型检查条件内完成,但似乎放弃了TypeScript的类型检查功能——添加any
注释和强制转换看起来真的不像";TypeScript方式"在这种情况下是什么?
解决方案是在这样的类型签名中使用双泛型,保持其他一切不变:
const myFunctionGeneric = function<K extends keyof Film, V extends Film[K]>(
film: Film,
filmPropertyName: K,
newValue: V
)
修改了这里的操场。