An Interest In:
Web News this Week
- March 24, 2024
- March 23, 2024
- March 22, 2024
- March 21, 2024
- March 20, 2024
- March 19, 2024
- March 18, 2024
Typescript Test Your Generic Type Part 2
read the part 1 here
now we know how to create tests for our type, but it is not done yet, there are edge cases that we need to take care of, and we need to understand some theories before we can solve them.
now take a look again at our Expect type
type Expect<T, U>= T extends U ? U extends T ? true : false : false
notice the T
and U
?
they are known as naked type parameters.
You can think of them as some kind of variable.
so if there are naked type parameters, then there are also non-naked type parameters and they look like this, examples:
- keyof T
- U[]
- [U]
- Partial< T >
naked parameter distributes over a union, while non-naked and types do not distribute over a union, to understand this, let's take a look at the code below
normal:
type A = "a" | "b" extends "a" ? true : false // false type B = "a" extends "a" | "b" ? true : false // true
pretty straightforward
"a" | "b"
cannot be narrowed down from "a"
, because "a" | "b"
is wider, so "a" | "b"
could not extend "a"
and vice versa
naked parameter:
type C<T,U> = T extends U ? true : falsetype r1 = C<"a" | "b", "a"> // booleantype r2 = C<"a", "a" | "b"> // true
in the case of r1, "a" | "b"
try to distribute over "a"
, "a"
extends "a"
is true
, "b"
extends "a"
is false
, in the end, we get true | false
which is also boolean
in the case of r2, "a"
is not a union, so there is no distribution, and since "a"
can be narrowed down from "a" | "b"
, hence we get true
By this point, we know what could go wrong with Expect, this time let us use Odd Number Type as our test subject
type OddNumber< X extends number, Y extends unknown[] = [1], Z extends number = never> = Y['length'] extends X ? Z | Y['length'] : OddNumber<X, [1, 1, ...Y], Z | Y['length']>type Expect<T, U> = T extends U ? (U extends T ? true : false) : false// eslint-disable-next-line @typescript-eslint/no-unused-varsexport const assert = <T extends true>() => { //}assert<Expect<OddNumber<5>,1 | 3 | 5>>() // true, pass test// @ts-expect-errorassert<Expect<OddNumber<5>,1>>() // false, fail test
as expected, it does not work.
so how can we fix it?
Actually the hint is already out there: non naked type parameters.
The solution is to convert the naked type parameter to the non-naked type parameter and the safest way is by turning them into arrays.
type Expect<T, U>= T[] extends U[] ? U[] extends T[] ? true : false : false
avoid turning them into a tuple, because the order of union cannot be guaranteed yet
type Expect<T, U>= [T] extends [U] ? [U] extends [T] ? true : false : false// don't do this
verify again with the example from part 1
great both of them are working!
this is the end of part 2, in part 3 we will going through more edge cases and further refine our Expect type
Original Link: https://dev.to/tylim88/typescript-test-your-generic-type-part-2-k2b
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To