简体   繁体   English

TypeScript - 获取通用 class 参数的类型

[英]TypeScript - get type of generic class parameter

I need to implement a type GetClassParameter<T> that would work like this:我需要实现一个像这样工作的类型GetClassParameter<T>

class Foo<T> {

}

type foo = Foo<string>

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

I'm sorry if it's a duplicate, I couldn't find it.对不起,如果它是重复的,我找不到它。 I only found a hardcoded solution ( source ):我只找到了一个硬编码的解决方案( source ):

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

I tried to do something like this:我试图做这样的事情:

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

The above almost works but requires BaseT to have a value: T property.以上几乎可以工作,但要求 BaseT 有一个value: T属性。

Is there a way to do it without hardcoding anything, assuming the target class has only one generic parameter?假设目标 class 只有一个通用参数,有没有办法在不进行任何硬编码的情况下做到这一点?

Update:更新:

Another take, unsuccessful.再接再厉,不成功。

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

Update 2更新 2

It's not possible currently.目前是不可能的。 Nevertheless, I tried a hack to define BaseT with value property and then removed it.尽管如此,我还是尝试了用 value 属性定义 BaseT 的技巧,然后将其删除。 It doesn't work.它不起作用。 I'm adding it as a reference if someone had a similar idea to save you time.如果有人有类似的想法以节省您的时间,我将其添加为参考。 playground 操场

Update 3更新 3

I'm adding a workaround I'm using to get the class parameter type for 2 classes that have nothing in common (it can be extended to cover more classes just by adding additional conditional).我正在添加一个解决方法,用于获取 2 个没有共同点的类的 class 参数类型(只需添加额外的条件,它就可以扩展到涵盖更多类)。

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

Cannot be done yet - purely as a type.还不能完成 - 纯粹作为一种类型。 There is an open issue that aims to allow passing higher-kind generic types through: https://github.com/microsoft/TypeScript/issues/1213有一个开放的问题旨在允许通过更高种类的泛型类型: https://github.com/microsoft/TypeScript/issues/1213

Its an issue that is a bane to many trying to type highly moddable js-libs (like levelup).对于许多尝试键入高度可修改的 js-libs(如 levelup)的人来说,这是一个问题。

Just to give you a much easier example of something that doesn't work:只是给你一个更简单的例子,说明一些不起作用的东西:

interface Dummy<T> {};

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

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

here a is unknown这里是unknown

the only real work around is to move the generic parameter into the dummy interface as a fake property - but then everything passed to this will need that fake property defined too - or you're back to 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 is now string but typescript still has no idea what P is a 现在是string ,但 typescript 仍然不知道P是什么

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM