Рассмотрим следующий фрагмент кода:
const f = (a: number, b?: string) => 2;
type ParametersOfF = Parameters<typeof f>; // [number, string?]
type AsTuple = [number, string?]; // [number, string?]
declare function g(...args: ParametersOfF): number; // function g(a: number, b?: string): number !!!
declare function h(...args: AsTuple): number; // function h(args_0: number, args_1?: string): number
Итак, ParametersOfF и AsTuple — это один и тот же тип. Но когда я определяю функции, которые принимают аргументы, эти два кортежа g имеют четко определенные имена аргументов a и b, а h имеет args_0 и args_1.
Отсюда и заголовок этого поста: Parameters<F> — это не простой кортеж, он также содержит имена каждого элемента в указанном кортеже. Глядя на то, как определяется Parameters, не помогает, это довольно просто. Так в чем магия?






Причина связана с внутренними компонентами компилятора, а не с самим типом Parameters. Любой подобный условный тип, который вы напишете, сохранит имена параметров.
Для кортежей, извлеченных из параметров, компилятор сохраняет ссылку на исходный параметр, из которого был извлечен каждый элемент кортежа. Когда кортеж распространяется обратно в функцию, используется исходное имя.
Эта ассоциация не является чем-то, что непосредственно видно из системы типов, и нет никакого способа установить это имя элемента кортежа, это скрытое свойство кортежа.
задокументировано здесь, «Обратите внимание, что когда тип кортежа выводится из последовательности параметров и затем расширяется в список параметров, исходные имена параметров используются в расширении (однако имена не имеют семантического значения и не наблюдаются в других случаях). "