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?
CodePudding user response:
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".
CodePudding user response:
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.
CodePudding user response:
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.
