Home > Enterprise >  Using one of objects properties value as type
Using one of objects properties value as type

Time:10-12

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


Playground

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

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.

  • Related