如何将类型参数传递给Typescript中的索引类型?

时间:2019-12-05 22:58:01

标签: typescript

我试图弄清楚如何在类中获取泛型函数的返回类型。

例如,

declare class Test {
    open<T, R>(t1: T, t2: R): T | R;
}

type TestType<T, R> = (Test['open'])<T, R>;

type TestTypeReturn = ReturnType<TestType<number, number>>;

但是,我在...])<T, R>的第4条非空白行出现错误,说应该使用分号。我不确定我想做什么。有人知道吗?

1 个答案:

答案 0 :(得分:1)

大概对于显示的特定示例,您可以手动写出所需的类型,例如:

type TestTypeManual<T, R> = (t1: T, t2: R) => T | R;
type TestTypeReturnManual = ReturnType<TestTypeManual<number, number>>; // number

但是您想让编译器为您完成这项工作。


TypeScript的类型系统缺乏表达表示通用函数类型(如{{1})的具体类型别名和引用type GenFunc = <T>(x: T)=>T的具体类型别名之间的关系所需的表达能力。您必须先调用通用函数,才能指定通用函数的类型参数。因此,即使有了上述内容,即使您可以调用类型为type GenAlias<T> = (x:T)=>T的函数,例如GenFunc,也没有像genFunc<string>("hello")这样的 type 。有一个开放的suggestion (microsoft/TypeScript#17574),它可能允许进行这种更高级别的操作,但我不知道我们是否可以期望在那里进行任何移动。

目前,似乎还没有办法完全在类型级别上做到这一点。


如果您不介意某些可能对所发出的JavaScript产生影响的hack,则可以利用对TypeScript 3.4中添加的inferring generic functions的某些支持。这就是我可能会做的。首先,在这样的地方引入函数声明:

GenFunc<string>

// you could just declare this instead of implementing it, but whatever: function magicThunk<A extends any[], R>(f: (...args: A) => R): () => (...args: A) => R { return () => f; } 函数可能只是采用了一个回调函数magicThunk()并返回了一个新的no-arg函数,该函数返回了f,这看起来并不神奇(但它是{{ 3}},至少)。但是,如果您使用通用函数调用f,那么从TS3.4开始会发生一件有趣的事情:

magicThunk()

返回的函数也是 泛型的,但是泛型类型参数已向移动了一层。现在,您可以调用thunk的泛型函数并指定其类型参数,从而获得非泛型函数:

const genericIdentity = <T>(x: T) => x; // <T>(x: T) => T
const thunkIdentity = magicThunk(genericIdentity); // <T>() => (x: T) => T

这正是我们想要的“指定通用函数的类型参数而不调用它”的操作。

无论如何,我们几乎都在那儿...最后一步是创建一个新的 generic const stringIdentity = thunkIdentity<string>(); // (x: string) => string; ,使我们能够将一些类型参数带入范围,而无需将它们直接放在另一个函数中。这是我为您的class类型执行的操作:

Test["open"]

现在class TransformTest<T, R> { open = magicThunk(new Test().open)<T, R>() } 的类型应该是您要寻找的类型:

TransformTest<T, R>.open

一切正常。请注意,您无需在代码中实际调用type TestType<T, R> = TransformTest<T, R>["open"]; // (t1: T, t2: R) => T | R type TestTypeReturn = ReturnType<TestType<number, number>>; // number 或构造magicThunk()的实例(这很好,因为我认为TransformTest不会被正确绑定);编译器在设计时就完成了您需要的所有工作;它只是必须经过评估将要发出的代码类型的动作。


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

thunk