TypeScript

时间:2019-01-16 21:42:54

标签: typescript generics type-systems

以下通用类型之间有什么区别?

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) }

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

如果<T>被定义为类/接口的必需泛型,例如Array<T>,然后方法od array可以成功推断T。但是,如果它在类/接口之外,则类型推断似乎不起作用。

1 个答案:

答案 0 :(得分:6)

两者在定义的功能签名上有很大不同。

  • 第一个定义了常规函数签名,使用时可以使用类型参数对其进行自定义,并且该类型变为固定在签名中
  • 第二个方法定义了通用函数签名,该函数可以接受任何类型的T参数,并在调用函数时推断(或明确指定)T
  • li>

请考虑以下声明:

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参数的函数分配给应该接受带有{{1}的任何类型的T参数的函数}由函数的调用者决定。只有通用函数才能满足类型T

FnWithParamInferred

我认为您真正想要的是能够从变量声明中忽略显式类型参数,并根据分配给它的值进行推断。 Typescript不支持此功能。如果为变量定义类型注释,则不会对该变量进行推断。

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

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

或者您可以定义一个通用的辅助函数来推断var f = (a: number) => { console.log(a) } // inferred as (a: number) => void ,但基于T限制函数签名

FnWithRequiredParam