Почему универсальный T выводится как литеральный тип только тогда, когда он имеет ограничение? - PullRequest
0 голосов
/ 02 ноября 2018

См. Следующий фрагмент

declare function foo<T>(a: T): (b: T) => boolean;

foo(111)(222);       // T inferred as 'number'
foo('hello')('bye'); // T inferred as 'string'

declare function bar<T extends number | string>(a: T): (b: T) => boolean;

bar(111)(222);       // T inferred as '111'
bar('hello')('bye'); // T inferred as 'hello'

площадка

Как вы можете видеть, функция bar выводит тип T в качестве литерального типа ('111' и 'hello' в примере), но в функции foo они выводятся как number или string, и единственным отличием является ограничение.

Любопытно, если использовать коробочные типы следующим образом

declare function baz<T extends Number | String>(a: T): (b: T) => boolean;

затем T выводится как number и string, но достаточно, чтобы один из них был примитивным типом, а T выводится как литеральный тип:

declare function brr<T extends Number | string>(a: T): (b: T) => boolean;

Итак, вопрос: Почему foo('hello') выводит T как string, но bar('hello') выводит T как 'hello'? Почему это происходит только тогда, когда T ограничено (по крайней мере, в этом примере)?

1 Ответ

0 голосов
/ 02 ноября 2018

Иногда требуется точный литеральный тип 'hello' для строкового литерала 'hello'. Иногда требуется более широкий, неспецифический тип string, выведенный для строкового литерала 'hello'.

Правила - когда следует выводить точный тип и когда тип должен быть расширен - прошли несколько итераций, здесь представлена ​​текущая реализация :

Во время вывода аргумента типа для выражения вызова тип, выведенный для параметра типа T, расширяется до его расширенного литерального типа, если:

  • все выводы для T были сделаны для вхождений T верхнего уровня в пределах определенного типа параметра, а
  • T не имеет ограничений или его ограничение не включает в себя примитивные или литеральные типы, а
  • T был исправлен во время вывода или T не встречается на верхнем уровне в типе возврата.
...