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

Mac*_*zyk 6 javascript typescript typescript-generics typescript-typings

我需要实现一个GetClassParameter<T>像这样工作的类型:

class Foo<T> {

}

type foo = Foo<string>

type x = GetClassParameter<foo>; // should be string
Run Code Online (Sandbox Code Playgroud)

很抱歉,如果它是重复的,我找不到它。我只找到了一个硬编码的解决方案(来源):

type GetFooParameter<T extends Foo<any>> = T extends Foo<infer R> ? R : unknown;
Run Code Online (Sandbox Code Playgroud)

我试图做这样的事情:

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
Run Code Online (Sandbox Code Playgroud)

以上几乎有效,但需要 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
Run Code Online (Sandbox Code Playgroud)

更新 2

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

更新 3

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

操场

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
Run Code Online (Sandbox Code Playgroud)

Mei*_*hes 4

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

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

只是为了给你一个更简单的例子来说明不起作用的事情:

interface Dummy<T> {};

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

let a = getParam(null as Dummy<string>);
Run Code Online (Sandbox Code Playgroud)

这里是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>);
Run Code Online (Sandbox Code Playgroud)

a 是现在string,但打字稿仍然不知道P是什么