I often get stuck with TypeScript, and when I do, I want to throw my Mac out of the window. So I’ve created this article, to help you and I write better code. I’ll be updating this post when I stumbled upon new and useful TypeScript hacks. In the meantime, feel free to get inspired to create your own cool TS magic, or to just steal some code, I won’t judge… 😜
First index of array
You might want to get the type of the first index in an array, and if so, this utility type is for you.
type First<T extends any[]> = T extends [infer P, ...any[]] ? P : never;
It’s a rather simple utility type to help you infer the type of the first index of an array.
type Test1 = First<[() => string, "a", "b"]>;
// ^ Test1: () => string
type Test2 = First<[undefined, 4]>;
// ^ Test2: undefined
type Test3 = First<[]>;
// ^ Test3: never
As a bonus, to get the last element of the tuple, change [infer P, ...any[]]
to [...any[], infer P]
!
If you’d like to use a variable of type tuple, you’ll be better off using the bracket notation to access the first element of the array, like this: T[0]
.
type First<T extends readonly any[]> = T[0];
And then pass the typeof
your tuple.
const numbers = [1, 2, 3, 4, 5] as const;
type Test = First<typeof numbers>;
// ^ Test: () => 1
Note: remember to cast your array as a const, using as const
, TypeScript will then infer it as readonly [1, 2, 3, 4, 5]
.
Infer the type of each element when using map()
Let’s say you have an array of vowels, or string[]
. Now, let’s say you want to loop over the array using Array.map()
. You would have something like this:
const vowels = ["a", "e", "i", "o", "u"];
vowels.map((v: string) => {});
// ^ v: string
An easy, yet underused approach is to cast the array to a tuple using as const
. Doing so will allow Array.map()
to return the possible values obtainable by Array.map()
. So now, your code should lok something like this.
const vowels = ["a", "e", "i", "o", "u"] as const;
vowels.map((v) => {});
// ^ v: "a" | "e" | "i" | "o" | "u"
Casting your array as a const
does come with a drawback, however. You won’t be able to mutate it after the fact. That means no more Array.push()
, Array.pop()
, etc…
Getting the length of a tuple
TypeScript is really clever, as it lets us access the prototype of an element. So instead of regular JS, where we use Array.length
, for TS Types, we can use any[]['length]
to access the length. And if that array turns out to be a tuple, TS can directly infer the length!
type Length<T extends readonly any[]> = T["length"];
Using it is simple, either pass a tuple directly into the type…
type Test1 = Length<["a", "b", "c"]>;
// ^ Test1: 3
Or, a more practical approach is to pass a variable of type tuple…
const letters = ["a", "b", "c"] as const;
type Test2 = Length<typeof letters>;
// ^ Test2: 3
Reminder: the above method only works with variables of type tuple, so arrays unfortunately will not work…
Conclusion
That’s it! I hope this helped someone out there. I’ll be updating this post when I stumble upon some other fancy TS trick. In the meantime, you can check out this post about Bun. It’s worth the read; I promise.
Thanks for reading 😊
Top comments (0)