TypeScript - 获取泛型类参数的类型

Posted

技术标签:

【中文标题】TypeScript - 获取泛型类参数的类型【英文标题】:TypeScript - get type of generic class parameter 【发布时间】:2021-07-10 19:44:47 【问题描述】:

我需要实现一个类型GetClassParameter<T>,它可以像这样工作:

class Foo<T> 



type foo = Foo<string>

type x = GetClassParameter<foo>; // should be string

对不起,如果它是重复的,我找不到它。我只找到了一个硬编码的解决方案(source):

type GetFooParameter<T extends Foo<any>> = T extends Foo<infer R> ? R : unknown;

我试图做这样的事情:

class Foo<T> 
    public value: T;
    public value2: string;
    constructor (value: T) 
        this.value = value;
    


type BaseT<T> = 
  value: T  // if removed, it wouldn't work

type GetClassParameter<T extends BaseT<any>> = T extends BaseT<infer R> ? R : unknown;

type x = GetClassParameter<foo> // string - almost works, requires shared property with a T

上述方法几乎可以工作,但要求 BaseT 具有 value: T 属性。

假设目标类只有一个通用参数,有没有办法在不硬编码的情况下做到这一点?

更新:

再拍一次,不成功。

type ClassLike<T> = (new <T>(...args: any[]) => any);
type GetClassParameter<T extends ClassLike<any>> = T extends ClassLike<infer R> ? R : unknown;
type x = GetClassParameter<foo> // error, does not satisfy constraint

更新 2

目前不可能。尽管如此,我还是尝试了用 value 属性定义 BaseT 的技巧,然后将其删除。它不起作用。如果有人有类似的想法以节省您的时间,我将其添加为参考。 playground

更新 3

我正在添加一个解决方法,用于获取 2 个没有共同点的类的类参数类型(只需添加额外的条件,它就可以扩展到涵盖更多类)。

playground

class Alpha<T> 
    private a: T;


class Beta<T> 
    private b: T;


type GetClassParameterForAlphaBeta<T extends Alpha<any> | Beta<any>> =
    T extends Alpha<infer R>
    ? R : T extends Beta<infer R>
    ? R : unknown;

type alpha = Alpha<string>
type beta = Beta<number>

type x = GetClassParameterForAlphaBeta<alpha> // string
type y = GetClassParameterForAlphaBeta<beta> // number

【问题讨论】:

我也尝试在类中使用这样的类型:type ClassRef&lt;T&gt; = (new (...args: any[]) =&gt; any);,但我不知道在右侧插入T 的位置。 并且TS不支持采用UtilType&lt;F&lt;T&gt;&gt; =&gt; T的一般形式的功能。 Higher kinded type 是术语,TS 没有。所以忘记完美的解决方案,你能得到的最好的解决方法是有限制的。您的两次拍摄实际上已经足够了。 我再也找不到问题了,但是如果没有使用泛型,打字稿会省略它们的信息。这是一个设计限制。 我没有更好的答案来解决你的问题,你已经达到了 TS 的极限。仅供参考,我在几年前写了一个关于 higher kinded type in TS 的答案。仅与您的问题远程相关。如果你想深入挖掘,可以看看。 感谢@hackape 【参考方案1】:

目前还不能完成 - 纯粹作为一种类型。有一个开放问题旨在允许通过更高种类的泛型类型:https://github.com/microsoft/TypeScript/issues/1213

对于许多尝试键入高度可修改的 js-libs 的人来说,这是一个祸根 (比如升级)。

只是给你一个更简单的例子来说明一些不起作用的东西:

interface Dummy<T> ;

declare function getParam<P, T extends Dummy<P>>(a: T): P;

let a = getParam(null as Dummy<string>);

这里是unknown

唯一真正的解决方法是将通用参数作为假属性移动到虚拟接口中 - 但随后传递给它的所有内容也需要定义该假属性 - 否则您将返回 unknown

interface Dummy<T> 
  a?: T
;

declare function getParam<P, T extends Dummy<P>>(a: T): T["a"]

let a = getParam(null as Foo<string>);

a 现在是 string,但 typescript 仍然不知道 P 是什么

【讨论】:

不相关,但可以在 Flow 中进行

以上是关于TypeScript - 获取泛型类参数的类型的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript泛型

在 Typescript 的泛型类中初始化泛型类型

180530-反射获取泛型类的实际参数

如何获取java泛型的参数类型

LayaBox---TypeScript---泛型

Kotlin泛型总结 ★ ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 | 可变参数结合泛型 | out 协变 | in 逆变 | reified 检查泛型参数类型 )