Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
November 22, 2021 04:46 am GMT

Infer in TypeScript, the Great and Powerful

Let's talk about the infer keyword in TypeScript. I believe, there're a lot of developers, who've been confused about infer. When should I use it? How it works? What is the purpose?

Confused developer

Let's start with something easier. The next cases will help us to understand the concept of infer. Ok, look at the piece of code:

let a = 10;

TypeScript infers a type quite smoothly it's a number. This fact allows developers to not write such types everywhere. TypeScript takes care of it. By the way, where will be another type in case of const usage. Try it by yourself. I'm waiting for your explanation in the comments. This is a small interactive with a reader)

Ok, we've just found out, TypeScript is pretty smart. If a value corresponds to a specific condition, TS can make a decision about its type. Something like this:

if (typeof a === 'number') {  return number;} else {  return ???;}

What does ??? mean?) Meet the never type. Looks quite useless, who'd like to use it? In TypeScript, never is treated as the no value type. Do we have any functions, which do not return a value (undefined is a correct value)? By the way, we can create such function. For example:

function foo() {  throw new Error('error');}

Check out the return type of foo.

Actually, the never type is not so useless. Let's come back to that example with number. We can use never in the else condition:

if (typeof a === 'number') {  return number;} else {  return never;}// ortypeof a === 'number' ? number : never;

Of course, where is no such code in TypeScript's codebase. It's just a model, how TypeScript works.

And there is an equivalent for if/else in TypeScript. I'm talking about the extends keyword:

type NumberFromType<T> = T extends number   ? number   : never;

Hm, there is something new <T>. Let's think about it like it is a box for a type. T can be any type. We will put the type into that box as soon as it will be defined anywhere in your statement. The classic example:

function test<T>(x: T): T {  return x;}test(10);

If you call it like test(10);, TypeScript will defined T as number, cause x was number. This is quite simple explanation, I know. But it's enough right now) Ok, we can moving on.

Let's come back to NumberFromType. T extends number means that its safe to assume that a value of type T is also of type number. For example, 10 extends number because let a: number = 10 is type-safe. Hm, what happens, if we pass a string into NumberFromType<T>? :

type A = NumberFromType<'10'>;// It will be treated like this:type NumberFromType<'10'> = '10' extends number ? number : never; 

As a result, there will be never in the type A, cause string is not extended from number. But what if we need to work with strings too? We can put one condition into another. Something like this:

type StringOrNumberFromType<T> = T extends string  ? string  : T extends number    ? number    : never

And voila, it works for strings and numbers) So, you can go deeper and put more conditions there, for each of type.

The infer keyword

Finally we are ready for infer! First of, the infer keyword can be used in conditional types only. And there is a really simple explanation you can not use it anywhere else =) This keyword doesn't have any meanings outside of a conditional type.

Ok, let's try to pass an array of numbers into NumberFromType. The result is never, obviously. An array of numbers is not extended from number. But what if we need to get a type of an array item? It can be something like this:

type ArrayItemType<T> = T extends ...

What should go next in that statement? We need to check, that T is an array:

type ArrayItemType<T> = T extends [] ? ... : never;

I've just finished the condition, like it was in NumberFromType. But the main question is not resolved, cause we need a type of the array's item. By the way, we can write a type for array of numbers like number[] or Array<number>. Any other type can be inside <> braces. So, our condition can be written in a such way:

type ArrayItemType<T> = T extends Array<ITEM_TYPE>   ? ITEM_TYPE   : never;

Ok, it's much better! But ITEM_TYPE is not defined. It has not been inferred yet. Yes, we need TypeScript to infer the type. We can ask TypeScript to do it:

type ArrayItemType<T> = T extends Array<infer ITEM_TYPE>   ? ITEM_TYPE   : never;

It means, if T is extended from an Array type, so, TypeScript, it would be really kind of you, if you will infer the type of T's item and will return it as a result.

In general, we can say, that the infer keyword and conditional typing in TypeScript allows us to take a type and isolate any piece of it for a later usage.

There are some real life examples.

Unpromisify

export type Unpromisify<T> = T extends Promise<infer Result>   ? Result   : never;

As it follows from its name, Unpromisify<T> returns a Promise's result. By the way, if you use TypeScript 4.5 or higher, you can use the built in type Awaited. There are some examples with Awaited on typescriptlang.org.

ComponentProps

In React, we often need to access prop types of a component. To do that, React offers a utility type for accessing prop types powered by the infer keyword called ComponentProps. You can find the full definition in DefinitelyTyped repository.

type ComponentProps<    T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>  > =        T extends JSXElementConstructor<infer P>            ? P            : T extends keyof JSX.IntrinsicElements                ? JSX.IntrinsicElements[T]                : {};

After checking that T is a React component (T extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>), it infers its props and returns them (T extends JSXElementConstructor<infer P> ? P). And the tail is about a simple React Element.

Conclusion

The infer keyword is a powerful tool that allows us to unwrap and store types from any complex type. It is like a type unboxing. So, there is no any mystery behind this keyword.

If you want challenge your TypeScript skills, I'd like to recommend you type-challenges. And I'm pretty sure, this post will be really useful. Enjoy)


Original Link: https://dev.to/artemmalko/infer-in-typescript-the-great-and-powerful-5cch

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To