user20216722
user20216722

Reputation:

Using one of objects properties value as type

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

Answers (3)

Tobias S.
Tobias S.

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".


Playground

Upvotes: 1

pigrammer
pigrammer

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"];

TypeScript Playground

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

Mike Lischke
Mike Lischke

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

Related Questions