Function Types: overloads, this, rest
Часто валят на нюансах: чем void отличается от undefined в return-позиции, что значит this-параметр, как работают overloads и почему лучше union вместо них. Красный флаг — писать overloads, когда хватает union, или возвращать boolean там, где нужен x is T.
void в TS — особый: callback, возвращающий что угодно, совместим с () => void.
const xs: number[] = [];function each<T>(arr: T[], fn: (x: T) => void) { arr.forEach(fn); }
// Этот callback возвращает number, но контракт принимает любую возвращаемую функциюeach([1, 2], x => xs.push(x)); // ок: push возвращает number, а контракт void
// Зато явный () => undefined — это уже именно undefinedconst f1: () => void = () => 42; // ок// const f2: () => undefined = () => 42; // ошибкаOverloads — устаревшая практика для большинства случаев; обычно лучше union/conditional types.
// Старый стиль — overloadsfunction get(key: 'name'): string;function get(key: 'age'): number;function get(key: string): unknown { return ({ name: 'Ada', age: 36 } as Record<string, unknown>)[key];}
// Современнее — обобщённая функция через keyoftype User = { name: string; age: number };const user: User = { name: 'Ada', age: 36 };function pick<K extends keyof User>(k: K): User[K] { return user[k]; }this-параметр — фейковый первый параметр для типизации контекста:
interface Btn { label: string }
function bindClick(this: Btn, e: { target: unknown }) { console.log(this.label, e.target);}// bindClick.call({ label: 'Ok' }, { target: null });Итог: Используй union/keyof вместо overloads, помни о специальном поведении void в callback-позиции, типизируй this, когда оно используется.