TypeScript Type Challenges: Mastering Type Lookup Techniques
Written on
Chapter 1: Understanding Type Lookup
In this segment of our TypeScript series, we'll explore the foundational concepts and strategies behind TypeScript. Specifically, we will focus on the new NoInfer utility in TypeScript 5.4 Beta, alongside useful tricks like as const and Extract. We will also delve into the challenge of implementing the Chainable utility type and using Mapped Types effectively.
To illustrate our point, we will tackle the challenge of retrieving the corresponding type by searching for a common type field within the union types of Cat | Dog. Our objective is to derive Dog for the lookup of 'dog' and Cat for the lookup of 'cat'. Here's the code example for clarity:
interface Cat {
type: 'cat';
breeds: 'Abyssinian' | 'Shorthair' | 'Curl' | 'Bengal';
}
interface Dog {
type: 'dog';
breeds: 'Hound' | 'Brittany' | 'Bulldog' | 'Boxer';
color: 'brown' | 'white' | 'black';
}
type Animal = Cat | Dog;
type LookUp<T, V> = {};
type cases = [
Expect<Equal<LookUp<Animal, 'dog'>, Dog>>,
Expect<Equal<LookUp<Animal, 'cat'>, Cat>>,
];
In this snippet, we utilize the Expect and Equal utility types. The definitions for these utilities are as follows:
type Expect<T extends true> = T;
type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false;
Solution Approach
To satisfy the conditions laid out in the LookUp test case, we need to assess whether the types align and evaluate each type in the union individually. This approach necessitates the use of conditional types in TypeScript, which follow the syntax:
T extends U ? X : Y
In this syntax, T, U, X, and Y are placeholders for types. Essentially, if T can be assigned to U, X is returned; otherwise, Y is returned. This is reminiscent of the ternary operator in JavaScript.
If you're unfamiliar with type placeholders, consider reviewing additional resources for a deeper understanding.
When evaluating conditional types, if the type being examined is a straightforward type parameter (not encapsulated in an array, tuple, promise, etc.), it is classified as a distributed conditional type. For distributed conditional types, when a union type is checked, it will create multiple branches during evaluation.
T extends U ? X : Y
T => A | B | C
A | B | C extends U ? X : Y =>
(A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y)
After grasping the concept of distributed conditional types, we can implement the LookUp utility type as follows:
type LookUp<U, T> = U extends { type: T } ? U : never;
Alternatively, we can leverage TypeScript's built-in Extract utility type:
type LookUp<U, T> = Extract<U, { type: T }>;
TypeScript is a powerful language worth mastering. If you're eager to learn more about TypeScript, feel free to connect with me on various platforms for further insights into TypeScript and JavaScript!
Type Lookup - TypeScript Type Challenges #62 [MEDIUM]
In this video, we dive into Type Lookup challenges in TypeScript, exploring practical examples and solutions.
Chapter 2: Exploring Includes
Includes with Aaron Harper - TypeScript Type Challenges #898 [EASY]
This session features a discussion on the Includes challenge in TypeScript, providing insights and tips for effective implementation.
Thank you for being part of the Plain English community! Be sure to engage with the content and follow for more updates on TypeScript and JavaScript!