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<T> = (new (...args: any[]) => any);
,但我不知道在右侧插入T
的位置。
并且TS不支持采用UtilType<F<T>> => 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 - 获取泛型类参数的类型的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin泛型总结 ★ ( 泛型类 | 泛型参数 | 泛型函数 | 多泛型参数 | 泛型类型约束 | 可变参数结合泛型 | out 协变 | in 逆变 | reified 检查泛型参数类型 )