0014 · First of Array
0014 · First of Array
Problem
Implement a generic First<T> that takes an array T and returns its first element's type.
type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]
type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3Solution
// Option 1: Conditional type approach
type First<T extends any[]> = T extends [] ? never : T[0]
// Option 2: Infer approach
type First<T extends readonly any[]> = T extends [infer F, ...infer R] ? F : neverExplanation
Naive Approach and Its Problem
The simplest idea is to just index the first element:
type First<T extends any[]> = T[0]This works for non-empty arrays, but when T is an empty array [], T[0] resolves to undefined instead of never. The test cases expect never for empty arrays.
Option 1: Conditional Type Guard
type First<T extends any[]> = T extends [] ? never : T[0]We explicitly check if T is an empty array. If it is, return never; otherwise return T[0].
Step by step:
T extends any[]— constrainsTto be an array typeT extends []— checks ifTis the empty tuple type- If empty →
never; otherwise →T[0](the first element)
Option 2: The infer Keyword
type First<T extends readonly any[]> = T extends [infer F, ...infer R] ? F : neverThis uses the infer keyword to pattern-match the tuple structure:
[infer F, ...infer R]matches any non-empty tuple, binding the first element toFand the rest toR- If
Tmatches (i.e., it's non-empty), returnF - If
Tis empty, the pattern doesn't match → returnnever
The
inferkeyword introduces a new type variable within a conditional type, letting TypeScript infer it from the matched structure.
Tips
readonly any[] is used instead of any[] so that the type works for both regular arrays and readonly tuples. A regular array is a subtype of a readonly array, so readonly any[] is the more general constraint.
Key concepts:
- Conditional Types —
T extends U ? A : B - Inferring Within Conditional Types — the
inferkeyword
中文解析
核心思路:
取数组第一个元素类型,看似简单,但需要处理空数组边界情况。
// 方案一:条件类型判断
type First<T extends any[]> = T extends [] ? never : T[0]
// 方案二:infer 模式匹配(更优雅)
type First<T extends readonly any[]> = T extends [infer F, ...infer R] ? F : never为什么不能直接用 T[0]?
type First<T extends any[]> = T[0] // ❌ 空数组时返回 undefined,而非 never空元组 [] 的索引 [0] 类型是 undefined,但题目期望返回 never。
方案一解析:
T extends []检查T是否为空元组- 如果是空元组 → 返回
never - 否则 → 返回
T[0](第一个元素)
方案二解析(推荐):
[infer F, ...infer R]是元组模式匹配infer F绑定第一个元素的类型...infer R绑定剩余元素的类型(这里用不到)- 空元组不匹配此模式 → 返回
never
考察知识点:
- 条件类型(Conditional Types)
infer关键字(类型推断)- 元组模式匹配(Tuple Pattern Matching)
