Обязательные и предполагаемые универсальные типы в TypeScript - PullRequest
0 голосов
/ 17 января 2019

В чем разница между следующими универсальными типами:

type FnWithRequiredParam<T> = (t: T) => void
type FnWithParamInferred = <T>(t: T) => void

Насколько я понимаю, FnWithRequiredParam всегда завершится ошибкой , если явно не задан универсальный тип в любом контексте. Передача универсального (который применяется), например, FnWithRequiredParam<string> в основном превратит его в (t: string) => void во всех контекстах.

Однако я не могу найти значение FnWithParamInferred. В некоторых контекстах <T> выводится из того места, где он используется (например, Array.map), но следующая строка выдает ошибку:

var f: FnWithParamInferred = (a: number) => { console.log(a) }

говорит, что number и T несовместимы. В строке выше, что на самом деле T? Он никогда не был объявлен точно и сравнивается с другим типом. Каковы правила определения универсального T, определенного в таких типах функций, как <T>(...) => ...?

Кажется, что, если <T> определен как обязательный универсальный класс для класса / интерфейса, например, Array<T>, то методы массива od могут успешно вывести T. Но если он находится за пределами класса / интерфейса, вывод типа не работает.

1 Ответ

0 голосов
/ 17 января 2019

Они сильно различаются в сигнатуре функции, которую они определяют.

  • Первый определяет сигнатуру обычной функции, которую можно настроить с помощью параметра типа при использовании, и этот тип становится фиксированным в сигнатуре
  • Второй определяет сигнатуру общей функции, то есть функцию, которая может принимать параметр любого типа T, причем T выводится (или указывается явно) при вызове функции.

Рассмотрим следующие объявления:

declare const fn: FnWithRequiredParam<number> 
declare const genericFn: FnWithParamInferred;

// T was fixed on declaration 
fn(1) // ok
fn("1") // err  

// T is decded by the caller
genericFn(1) // ok T is number for this call
genericFn("1") // ok T is string  for this call
genericFn<number>("1") // err T was specified as number but string was passed in 

Причиной ошибки, которую вы получаете, является то, что вы пытаетесь присвоить функцию с параметром number функции, которая должна принимать параметр любого типа T, причем T определяется решением вызывающая функция. Только универсальная функция может удовлетворить тип FnWithParamInferred

var f: FnWithParamInferred = <T>(a: T) => { console.log(a) }

Я думаю, что вы действительно хотите, чтобы иметь возможность пропустить явный аргумент типа из объявления переменной и сделать его вывод основанным на присвоенном ему значении. Typescript не поддерживает это. Если вы определите аннотацию типа для переменной, то для нее не будет никакого вывода.

Вы можете вообще пропустить аннотацию типа, чтобы компилятор мог определить тип функции:

var f = (a: number) => { console.log(a) } // inferred as (a: number) => void

Или вы можете определить универсальную вспомогательную функцию для вывода T, но ограничить сигнатуру функции на основе FnWithRequiredParam

function createFunction<T>(fn: FnWithRequiredParam<T>) {
    return fn;
}

var f = createFunction((a: number) => { console.log(a) }) // inferred as FnWithRequiredParam<number>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...