如何从类型中检索泛型属性的类型?

时间:2019-04-06 07:43:58

标签: typescript

type Parent = {
    fun<T>(a: T, b: string):void
}
type ChildFunArgs = Parameters<Parent['fun']<number>> // got an error

如果上面的代码可以运行,那么我可以这样做:

const childFunArgs: ChildFunArgs = [1, '1']

2 个答案:

答案 0 :(得分:2)

没有高阶类型操纵可完全在类型系统中自动为您执行此操作。

如果您可以接受对运行时影响较小(意味着它会发出一些JS代码)并且外观丑陋的类型修改,请使用(如果您使用的是TypeScript 3.4及更高版本),则可以您的类型如下:

const dummyParams =
    ((x => () => x) as <A extends any[]>(
        f: (...args: A) => any) => () => A
    )(null! as Parent['fun'])<number>();
type ChildFunArgs = typeof dummyParams
// type ChildFunArgs = [number, string]

您可以验证ChildFunArgs是您期望的类型。在运行时,发出的代码本质上是

const dummyParams = ((x => () => x))(null)();

具有相同的作用
const dummyParams = null;

因此对运行时有影响,但影响很小。


这些丑陋的东西如何工作?我们正在欺骗编译器以为我们拥有这样的功能:

declare function params<A extends any[]>(f: (...args: A)=>any): () => A;

此假设的params()函数将接受函数参数f,并返回一个新的零参数函数,该函数返回一个类型为f的参数类型的元组。嗯,这令人困惑。我的意思是params((x: string, y: boolean)=>123)将返回类型为() => [string, boolean]的新函数。这样的功能基本上是不可能实现的,但我们不必真正实现它。

然后我们假设我们有一个fun的{​​{1}}方法类型的值:

Parent

我们在其上拨打 declare const parentFun: Parent['fun'];

params

由于最近的improvements in higher-order function handling,编译器推断const paramsParentFun = params(parentFun); // const paramsParentFun: <T>() => [T, string] 的类型为paramsParentFun。现在,您可以假装调用 this 函数,并为<T>() => [T, string]手动指定number

T

瞧!您会找到想要的东西。

上面的较短代码与此相同,但是它使用type assertions向编译器撒谎说明这些其他函数和值的存在,从而使发出的JavaScript不会产生额外的混乱。

好的,希望能有所帮助。祝你好运!

答案 1 :(得分:0)

如果您使用接口而不是Parent的类型,则可以。

它看起来像这样:

interface Parent<T> {
    fun(a: T, b: string):void
}

type ChildFunArgs = Parameters<Parent<number>['fun']> 

const childFunArgs: ChildFunArgs = [1, '1']

您可以看到它在here下工作。