Reputation:
TS beginner. Here
let test = <T,>(x:T, c:{[k in keyof T]:(p:T[k])=>void})=>{
}
test({name:"john"}, {name:(functionParam)=>null})
The functionParam
is resolved as string
. But I used T[k]
which refers to "john"
. So is it correct that it got inferred as string
?
Where can I read more about this?
Upvotes: 1
Views: 647
Reputation: 23905
You are observing type widening which happens in this case because there is no constraint on T
and T
also does not directly infer the string type. You can read more about the specifics in this Pull request.
To solve this, add an extra generic type S
which extends string
(or any other primitive type which may be valid here). T
will be constrained to Record<string, S>
.
let test = <
T extends Record<string, S>,
S extends string
>(x: T, c:{ [K in keyof T] : (p:T[K]) => void })=> {}
test({ name:"john" }, { name:(functionParam) => null })
// ^? "john"
Now, the parameter functionParam
is correctly inferred to the string literal type "john"
.
Upvotes: 1
Reputation: 3509
Yes, this is correct. In TypeScript, you can index a type to get the type of the property of that key (see Indexed Access Types). Basing a type on the value of an object's property is impossible, as TypeScript runs at compile time and values are determined at runtime. If you had a type "john"
then that is what would show up:
type John = {name: "john"};
let yourName: John["name"];
You can see that the type of yourName
is then "john"
. By default, TypeScript assumes that the object will change, so the type of
let me = {name: "john"};
is inferenced as {name: string}
(TypeScript Playground). If it was {name: "john"}
by default, then you couldn't change it to something else. Most of the time, when you declare an object, you're going to change it, so this is the safe assumption to make.
Upvotes: 1
Reputation: 53532
I'm not aware of a specific name of this features. It's the keyof operator you apply here.
The keyof operator takes an object type and produces a string or numeric literal union of its keys.
Your object type T
is { name: "john" }
. The result of keyof
is hence "name" and T[k]
returns therefore "john", which is widened to string
.
Upvotes: 2