Advanced TypeScript Exercises - Answer 1

macsikora

Pragmatic Maciej

Posted on February 7, 2020

Advanced TypeScript Exercises - Answer 1

The Question I've asked was:

If we have a type which is wrapped type like Promise. How we can get a type which is inside the wrapped type? For example if we have Promise<ExampleType> how to get ExampleType?

The answer

type Transform<A> = A extends Promise<infer Inner> ? Inner : never
type Result = Transform<Promise<string>> // Result is string type
Enter fullscreen mode Exit fullscreen mode

In order to unwrap the promise type we have used infer keyword.

The keyword is helpful with any type constructor, type constructor is a type parameterized by another type variable, so any type which has generic placeholder like A<B>, where A is type constructor parametrized by B.

Examples of using infer

We can use infer also with other types, consider example with Array

type InsideArray<A> = A extends Array<infer Inside> ? Inside : never
type Str = InsideArray<Array<string>>; // Str is string
Enter fullscreen mode Exit fullscreen mode

What about custom parameterized types? Yes will do!

type Surprise<A> = { inside: A }
type UnpackSurprise<S> = S extends Surprise<infer Inside> ? Inside : never
type Num = UnpackSurprise<Surprise<number>> // Num is number
Enter fullscreen mode Exit fullscreen mode

We can even use infer to get mapped types properties

type User = {
    id: number,
    name: string,
}

type Doc = {
    id: string,
}

type GetProperty<T, Prop extends keyof T> = T extends { [K in Prop]: infer Value } ? Value : never

type UserId = GetProperty<User, 'id'>
type DocId = GetProperty<Doc, 'id'>
Enter fullscreen mode Exit fullscreen mode

Question How we can get type of Mapped type property in simpler way? Please write your answer in the comment!

Can we use many type variables and infer them? Sure we can!

type ABC<A, B, C> = { a: A, b: B, c: C }
type ABCIntoTuple<T> 
  = T extends ABC<infer A, infer B, infer C> ? [A, B, C] : never
type Example = ABC<string, boolean, number>
type ExampleTuple = ABCIntoTuple<Example> // [string, boolean, number]
Enter fullscreen mode Exit fullscreen mode

In above example we infer all three type parameters and we put them into 3-n tuple.

Why never?

Type never is a bottom type, it is a type without any value, it is very handy construct for saying that our function doesn't return, or some path of the code is not reachable, more about it you can read in great article from Marius Schulz.

We use never in conditional in order to represent the unhappy path, we are saying that it is a dead end, if you don't pass to our constructor specific type, we just don't have any alternative, our type doesn't work with anything else. Consider how it will behave when we pass to it something which does not match the condition:

type Transform<A> = A extends Promise<infer Inner> ? Inner : never
type OhGosh = Transform<string> // OhGosh evaluates to never
Enter fullscreen mode Exit fullscreen mode

We could be having different representation of the negative path, but never is the best choice, as further type transformation will be useless. We can also set constraint at the argument, and in that way never path will never be reached.

Consider following change:

type Transform<A extends Promise<any>> = A extends Promise<infer Inner> ? Inner : never
type OhGosh = Transform<string> // compilation error
Enter fullscreen mode Exit fullscreen mode

After A extends Promise<any> our utility type Transform is now bullet proof, as compilation will fail for types which do not extend Promise<any>.

Why did I use Promise<any>?

I have put any inside Promise because any is one of unsound types which are also types which can be assigned to everything, it means that every type extend from any, what determines that every Promise kind of type will extend Promise<any>

This series is just starting. If you want to know about new exciting questions from advanced TypeScript please follow me on dev.to and twitter.

đź’– đź’Ş đź™… đźš©
macsikora
Pragmatic Maciej

Posted on February 7, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related