Lio*_*Tay 7 generics typescript keyof
有没有办法进行以下类型检查?
function getNumberFromObject<T>(obj: T, key: keyof T): number {
return obj[key] // ERROR: obj[key] might not be a number
}
Run Code Online (Sandbox Code Playgroud)
我想指定它key不仅应该是 的键T,而且应该是带有number值的键。
jca*_*alz 10
这样做的最直接的方法是调用者和getNumberFromObject<T>类型检查的实现都正确是这样的:
function getNumberFromObject<T extends Record<K, number>, K extends keyof any>(
obj: T,
key: K
): number {
return obj[key] // okay
}
Run Code Online (Sandbox Code Playgroud)
当你调用它时:
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "dog"); // okay
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "cat"); // error
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "moose"); // okay
getNumberFromObject({dog: 2, cat: "hey", moose: 24}, "squirrel"); // error
Run Code Online (Sandbox Code Playgroud)
一切都很好,只是你得到的错误有点模糊,因为它抱怨Object literal may only specify known properties, and 'dog' does not exist in type 'Record<"somebadkey", number>'. 这个投诉是多余的财产检查,并不是真正的问题。
如果你想让调用者得到更好的错误,你可以使用更复杂的条件类型,如下所示:
function getNumberFromObject<T, K extends keyof any & {
[K in keyof T]: T[K] extends number ? K : never
}[keyof T]>(
obj: T,
key: K
): T[K] {
return obj[key] // okay
}
getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "dog"); // okay
getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "cat"); // error
getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "moose"); // okay
getNumberFromObject({ dog: 2, cat: "hey", moose: 24 }, "squirrel"); // error
Run Code Online (Sandbox Code Playgroud)
在这种情况下,T是不受约束的,但K被迫只是来自Twhere T[K]is a 的那些键number。
现在错误为Argument of type '"somebadkey"' is not assignable to parameter of type '"dog" | "moose"'.,这对开发人员更友好。不过,不确定签名的额外复杂性对您来说是否值得。
希望有帮助。祝你好运!
更新:后一个函数返回T[K],而不是number。这可能是一件好事,因为T[K]可能比number. 例如:
interface Car {
make: string,
model: string,
horsepower: number,
wheels: 4
}
declare const car: Car;
const four = getNumberFromObject(car, 'wheels'); // 4, not number
Run Code Online (Sandbox Code Playgroud)
该值four的类型为4,它比 更具体number。如果你真的想将函数的返回类型扩大到number,你可以......尽管实现会犹豫不决,因为编译器不够聪明,无法意识到在泛型情况下T[K]可以分配给number。有很多方法可以解决这个问题,但最简单的方法是在实现 ( return obj[key] as any as number) 中使用类型断言。