TypeScript中必需与推断的泛型类型

duc*_*cin 3 generics type-systems typescript

以下泛型类型有什么区别:

type FnWithRequiredParam<T> = (t: T) => void
type FnWithParamInferred = <T>(t: T) => void
Run Code Online (Sandbox Code Playgroud)

据我所知,如果没有在任何上下文中明确给出泛型类型,FnWithRequiredParam则总是会失败.传递泛型(强制执行),例如,基本上将它转换为所有上下文.FnWithRequiredParam<string>(t: string) => void

但是,我找不到的意思了FnWithParamInferred.在某些上下文中<T>,从它使用的位置(例如Array.map)推断,但是以下行会引发错误:

var f: FnWithParamInferred = (a: number) => { console.log(a) }
Run Code Online (Sandbox Code Playgroud)

numberT不兼容.在上面这行,究竟是T什么?它从未被精确地声明,并且正在与另一种类型进行比较.确定T函数类型中定义的泛型是什么规则是什么<T>(...) => ...

似乎,如果<T>被定义为类/接口的必需泛型,例如Array<T>,那么方法od数组可以成功地推断出来T.但是如果它在类/接口之外,类型推断似乎不起作用.

Tit*_*mir 10

这两者在他们定义的功能签名上非常不同.

  • 第一个定义了常规函数签名,可以在使用时使用类型参数进行自定义,并且该类型变为固定到签名中
  • 第二定义了一个通用的函数签名,即,可以接受任何类型的参数的函数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 
Run Code Online (Sandbox Code Playgroud)

之所以你所得到的错误是,你正试图分配功能与number参数应该接受任何类型的参数的功能T,与T由函数的调用者来决定.只有通用函数才能满足该类型FnWithParamInferred

var f: FnWithParamInferred = <T>(a: T) => { console.log(a) }
Run Code Online (Sandbox Code Playgroud)

我认为你真正想要的是能够从变量声明中省略显式类型参数,并根据分配给它的值来推断它.Typescript不支持这个.如果为变量定义类型注释,则不会对变量进行推理.

您可以完全省略类型注释,让编译器推断出函数类型:

var f = (a: number) => { console.log(a) } // inferred as (a: number) => void
Run Code Online (Sandbox Code Playgroud)

或者您可以定义一个通用的辅助函数来推断T,但是可以根据它来限制函数签名FnWithRequiredParam

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

var f = createFunction((a: number) => { console.log(a) }) // inferred as FnWithRequiredParam<number>
Run Code Online (Sandbox Code Playgroud)