如果我具有以下功能:
function test<T, K extends keyof T>(o: T, propertyValue: T[K], propertyName: K) {
// ... do something
}
我这样做:
interface Car {
manufacturer: string;
model: string;
year: number;
}
let taxi: Car = {
manufacturer: 'Toyota',
model: 'Camry',
year: 2014
};
test(taxi, 0, 'model');
编译器能够检测到模型属性不是字符串类型,因此测试调用行失败。但是,如果我尝试在像这样的界面中使用索引类型:
export interface Change<T, K extends keyof T = keyof T> {
timestamp: number;
field: K;
value: T[K];
}
const change: Change<Car> = {
timestamp: 1484684700749,
field: 'model',
value: 0
};
它可以编译。即使实际上由字段指定属性,它也允许您将值设置为字符串或数字。我是在做错什么,还是由于编译器的工作原因,在这种情况下是不可能的?
您可以看到实际示例here in ts playground
答案 0 :(得分:1)
那是因为K
可以是T
的任意键,打字稿不知道是哪一个。
考虑以下示例:
const makeChange = (args: any): Change<Car> => {
// some logic to return the change here.
}
Change<Car>
现在应K
使用什么类型。由于field
的值是在运行时确定的,因此无法在编译期间分配静态类型。
一种解决方法,可以定义您的Change
类型,如下所示:
interface Change<T, K extends keyof T> {
timestamp: number;
field: K;
value: T[K];
}
const change: Change<Car, 'model'> = {
timestamp: 1484684700749,
field: 'model',
value: 0 // not working as expected.
};
您需要在类型中指定字段(通用参数K
),才能进行静态类型检查。
如果您在其他部分使用Change
接口并且不使用特定字段,则始终可以向函数添加通用类型,如下所示:
const uploadChange = <K extends keyof Car>(change: Change<Car, K>) => {
// ...
}