Reputation: 436
Typescript doesn't allow infering a type to the object using in-operator.
For example,
function getKey<T extends object, U extends string> (obj: T, key: U) {
if (key in obj) {
return obj[key] // Type 'U' cannot be used to index type 'T'.
}
}
Typescript should recognize that U is keyof T, so I could use it as a key.
How can i solve this without the need to using any?
Upvotes: 1
Views: 151
Reputation: 249536
You need to declare U
as extending keyof T
in order to use it for indexing an object without a string
indexer.
function getKey<T extends object, U extends keyof T> (obj: T, key: U) {
if (key in obj) {
return obj[key] // Now works!
}
}
As the PR for in
type guards suggest the guard impacts the type of T
not the type of the key, so you still need to explicitly tell the compiler that U
extends keyof T
If you want to keep U
as string
(and I would encourage you to consider if you really need it to be a type parameter and you can't just use string
for the argument) you can have multiple signatures for the function :
// The visible signatures of the function
// The first one takes keyof T and infers return type based on it
function getKey<T extends object, U extends keyof T> (obj: T, key: U) : T[U]
// The second one takes string and will return any
function getKey<T extends object> (obj: T, key: string) : any
// The implementation signature allows indexing, this will not be public.
function getKey(obj: { [index: string]: any }, key: string) {
if (key in obj) {
return obj[key] // Can now index T
}
}
let r = getKey({ type: "test"}, "type"); // r is infered to `test`
let r2 = getKey({ type: "test"}, "notAProp"); // r is infered to any
Upvotes: 2