Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
June 19, 2022 08:08 pm GMT

How to test your typescript utility types

Typescript has some nice utility types to help you improve code typing.

As a reminder, utility types, are like functions but for types. What this means is that utility types take types as parameters and return types as output.

For example the utility named Parameters<T> is defined like this :

type Parameters<T extends (...args: any) => any> =      T extends (...args: infer P) => any ? P : never;

It takes any function type as a parameter and returns a Tuple of all the function parameters.

Sometimes you need to create your own custom utility types.

And if usually you add some unit tests for your functions, you might also want to do the same for your utility type.

But how to test them ? Does this mean that tests are run at compile time and fail to report errors at runtime ? can you do these tests with your favorite test Runner ?

Utility to compare two types

First of all, if you want to test your utility types, at the minimum we will need to compare the output of your utility type to the expected one.

First try

One could try to do this :

type Equals<T,U> = T extends U ? U extends T ? true : false : false;

This will work until you realise that this returns true :

type Test = Equals< 1, 1 | 2 >;

This is due to how typescript conditional types work. It's doing distributive conditional typing.

Since we want to do strict type equality, we want to disable distributive behaviour.

Disabling distributive conditional typing

One way of doing it is to hide the type you want to test inside. For example, like this :

type Equals<T,U> = [T] extends [U] ? [U] extends [T]? true: false : false;

Now :

type Test = Equals< 1, 1 | 2 >;

returns false.

But we are not there yet. Indeed, because of any, this will return true :

type Test = Equals< any, 1 | 2 >;

Solution

type Equals<T, U> =    (<V>() => V extends T ? 1 : 2) extends    (<V>() => V extends U ? 1 : 2) ? true : false;

This solution relies on internal understanding of Typescript isTypeIdenticalTo. For a more detailed explanation, you can check this issue

How to use it to run your utility type tests

When writing tests, you need to have a something to help you diagnose the issue, a readable message.

So you can write the previous test like this :

type Assert<T, U> =    (<V>() => V extends T ? 1 : 2) extends    (<V>() => V extends U ? 1 : 2) ? true :     { error: "Types are not equal"; type1: T; type2: U };

Now when Assert checks that two types are not equal, you'll get a nice message.

And you can use it like this :

const test1: Assert<Parameters<(a: number)=>void>,[number]> = true; // passconst test2: Assert<Parameters<(a: number)=>void>,[string]> = true; // fail

Conclusion

By using this Assert utility type (you can even use it to test itself) you'll be able to add unit tests for your own utility types.

This will show you a nice message as to why it fails and where. It will allow you to monitor typescript regressions in the type system for your utility types.

if you want to see it in practice, you can check some tests here for zodios library.

If this article was helpfull to you, don't forget to give it a thumbsup.


Original Link: https://dev.to/ecyrbe/how-to-unit-test-your-typescript-utility-types-3cnm

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