Home > OS >  Why "in" operator wasn't suitable here?
Why "in" operator wasn't suitable here?

Time:10-20

In attempt to make type which should be values of given object type I started with this:

type Book = {
  name:string,
  year:number,
  author:string
}

// expected result "string" | "number"
type ValueOf<T extends {}> = T[k in keyof T] // error due to "in"

let x:ValueOf<Book> ; 

But seems in is redundant here. I could just have used T[keyof T].

While I have seen in operator in similar cases like this:

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};

Why wasn't it needed in my case? What concept did I miss related to in usage? What is rule of thumb when I could use in?

CodePudding user response:

in in your example is for Mapped types.

What you want is :

type ValueOf<T extends {}> = T[keyof T] 

type foo =  ValueOf<Book> ; // string | number

Playground


A Mapped type is a generic type which uses a union of PropertyKeys (frequently created via a keyof) to iterate through keys to create a type. I mostly look like :

{ [Property in keyof Type]: whatEverType; }

CodePudding user response:

Mapped types

in should be used in mapped types such as the last type in your question:

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};

In mapped types, you are building a new object type through iteration:

keyof Book = 'name' | 'year' | 'author'
OptionsFlags<Book> = {
  name: boolean;
  year: boolean;
  author: boolean;
}

Indexed Access Types

Your ValueOf type is an indexed access type so you should remove the k in:

type ValueOf<T extends {}> = T[keyof T];

In an indexed access type you are accessing the type of the value for the key you pass between angle brackets:

type BookName = Book['name'] // string

But the key can also be an union type, which is the case of keyof T.

You may read this as "What types do I get when I go through all these key values?" (that would be a kind of projection in my mind). And with your Book type, Typescript would go through all these steps:

ValueOf<Book>
=> Book[keyof Book]
=> Book['name' | 'year' | 'author']
=> Book['name'] | Book['year'] | Book['author']
=> string | number | string
=> string | number
  • Related