Загрузка…
Загрузка…
TypeScript · senior · сложность 8
Пересобрать стандартные utility-типы — частая whiteboard-задача:
// Rebuild the standard-library conditionals — a frequent whiteboard task
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type MyParameters<T> = T extends (...args: infer P) => any ? P : never;
type MyNonNullable<T> = T extends null | undefined ? never : T;
type MyAwaited<T> = T extends Promise<infer U> ? MyAwaited<U> : T; // recurse to unwrap nesting
type R = MyReturnType<(x: number) => string>; // string
type A = MyAwaited<Promise<Promise<number>>>; // number// The distribution gotcha, made explicit
type Wrap<T> = T extends any ? { v: T } : never;
type Distributed = Wrap<'a' | 'b'>; // { v: 'a' } | { v: 'b' }
type Blocked = [('a' | 'b')] extends [any] ? { v: 'a' | 'b' } : never; // { v: 'a' | 'b' }
// Why NonNullable is written with a naked T: it must distribute to filter each member
type Clean = MyNonNullable<string | null>; // stringMyNonNullable с «голым» T распределяется по union и выкидывает null/undefined из каждого члена. Обёртка в tuple блокирует distribution — получается один объектный тип вместо union объектов.
Умение переписать ReturnType, Awaited, NonNullable и показать distribution vs tuple — базовый сеньорский минимум по conditional types.