# 32427-Unbox
# 题目描述
实现 Unbox<T, N?>,把数组 / 元组 / 函数返回值 / Promise 这些"盒子"层层剥开:
- 基础:
Unbox<T>剥一层盒子(无盒子则原样返回)。 - 进阶:默认情况下递归剥到底。
- 再进阶:第二个参数
N可控制剥的层数,N = 0表示无限剥,N >= 1表示剥N层。
type A = Unbox<number[]>; // number
type B = Unbox<() => Promise<() => number>>; // number
type C = Unbox<() => () => () => number, 2>; // () => number
type D = Unbox<Promise<Promise<number>>, 0>; // number (0 代表剥到底)
# 分析
分两步:
- 实现
UnboxOne<T>:根据T的形态判断它是不是数组 / 元组 / 函数 / Promise,剥一层。 - 套个带计数器的递归:
- 如果
N = 0,一直剥到盒子里不再是盒子(即UnboxOne<T> = T)为止; - 如果
N >= 1,计数累到N就停,不管底层还有没有盒子; - 途中如果已经剥到"非盒子",也直接结束。
- 如果
匹配数组、元组、函数、Promise 的 infer:
- 数组和元组:
T extends (infer U)[] ? U可以同时命中number[]和[number](元组也 extendsany[])。 - 函数:
T extends () => infer U ? U。 - Promise:
T extends Promise<infer U> ? U。
注意匹配顺序:先匹 Promise、再匹数组/元组、最后匹函数——因为 Promise 的内部并不是函数形态,但数组和函数互斥,顺序基本无所谓。
# 题解
type UnboxOne<T> = T extends Promise<infer U>
? U
: T extends (infer U)[]
? U
: T extends () => infer U
? U
: T;
type Unbox<T, N extends number = 0, C extends any[] = []> = N extends 0
? // 无限剥:剥到底就停
UnboxOne<T> extends T
? T
: Unbox<UnboxOne<T>, 0>
: // 计数剥:剥到 N 层或剥不动就停
C['length'] extends N
? T
: UnboxOne<T> extends T
? T
: Unbox<UnboxOne<T>, N, [...C, 1]>;
解读:
UnboxOne<T>:只剥一层。若T不是任何盒子,直接返T,所以UnboxOne<UnboxOne<...>> = T就意味着已经剥到头。N = 0分支:靠UnboxOne<T> extends T判断是不是"盒子里的东西等于盒子自身"——这是到底的信号,直接返回T。否则把UnboxOne<T>继续往下递归。N >= 1分支:额外维护一个长度计数元组C,每一层递归C增一个元素;C['length'] extends N即剥满了。若中途已经剥到头(UnboxOne<T> extends T),也直接停。
# 验证
type cases = [
Unbox<number>, // number
Unbox<() => number>, // number
Unbox<number[]>, // number
Unbox<[number]>, // number
Unbox<Promise<number>>, // number
Unbox<() => Promise<() => Array<Promise<boolean>>>>, // boolean
Unbox<() => () => () => () => number, 1>, // () => () => () => number
Unbox<() => () => () => () => number, 4>, // number
Unbox<Promise<Promise<Promise<number>>>, 2>, // Promise<number>
];
# 知识点
(infer U)[]一次性覆盖number[]和[number](元组是数组的子类型),是消除"数组 / 元组"类题目分支的捷径。- 递归 + "固定点检测"(
UnboxOne<T> extends T即剥不动了)是无限剥类题目的通用写法。 - 用元组
C做步数计数、C['length'] extends N做出口,是类型层做"有限循环"的标准手段,见 进阶-计数-加减乘除。