Type Inference Pitfalls
Topic для разговора с senior’ом: где TS «угадывает» неудачно. На интервью спросят про widening литералов, контекстуальную типизацию callback’ов, проблему const arr: string[] = [‘a’,‘b’] теряет литералы. Красный флаг — лепить везде as const, когда хватает satisfies.
Widening литералов и решение через as const / satisfies:
const o1 = { dir: 'asc' }; // { dir: string } — широкоconst o2 = { dir: 'asc' } as const; // { readonly dir: 'asc' }const o3 = { dir: 'asc' } satisfies { dir: 'asc' | 'desc' };// o3.dir — 'asc', при этом проверено, что значение валидно для unionContextual typing в массивах и колбэках:
// Без явного типа массива literal'ы расширяются до stringconst tags1 = ['a', 'b']; // string[]const tags2 = ['a', 'b'] as const; // readonly ['a', 'b']
// Внутри map TS типизирует параметр по контексту[1, 2, 3].map((n /* number */) => n * 2);
// А вот вытащенный callback теряет контекстconst double = (n) => n * 2; // n: any (без noImplicitAny — ошибка)Generic-инференс: TS не «домысливает» из возврата, и NoInfer (TS 5.4+) помогает закрепить ожидание:
function pickDefault<T>(items: T[], fallback: NoInfer<T>): T { return items[0] ?? fallback;}
pickDefault([1, 2, 3], 0); // T = number// pickDefault<number>(['a','b'], 0); // ошибка: 'a' не number// без NoInfer: TS вывёл бы T = number | string из обоих аргументовИтог: Инференс расширяет литералы, теряет контекст вне обёртывающего вызова и «усредняет» T по всем источникам — satisfies, as const и NoInfer правят это явно.