获取使用泛型的函数的返回类型

25
免责声明:以下是过于简化的函数,我知道它们是无用的。
function thinger<T>(thing: T): T {
    return thing;
}

const thing = thinger({ a: "lol" });

thing.a;

上述代码可以顺利转译。但我需要将thinger<T>的结果放入一个对象中。
interface ThingHolder {
    thing: ReturnType<typeof thinger>;
}

const myThingHolder: ThingHolder = {
    thing: thinger({ a: "lol" }),
};

然而,我丢失了类型信息,因此myThingHolder.thing.a无法工作。

属性“a”在类型“{}”上不存在。

因此,我尝试了以下方法:

interface ThingHolder<T> {
    thing: ReturnType<typeof thinger<T>>;
}

const myThingHolder: ThingHolder<{ a: string }> = {
    thing: thinger({ a: "lol" }),
};

但是 typeof thinger<T> 在 TypeScript 中是无效的。

如何获取一个函数的返回类型,该函数的返回类型基于泛型而异?


1
自己摸索有什么不好的呢?interface ThingHolder<T> { thing: T } - jcalz
2
正如我在帖子开头的免责声明中所述,我意识到在这个过于简化的示例中,我应该这样做,但我的实际用例并不那么简单。我有一个接受许多泛型并返回比这些泛型更复杂的东西的函数(但是泛型仍然会影响返回类型)。 - ed'
3
我可以写,但这样会非常冗长,并且每次函数更改时都需要重写。说实话,即使这是一个合理的解决方案,我仍然想要这个问题的答案。 - ed'
2
简短的回答是“TypeScript无法做到这一点”,因为它既没有泛型值,也没有高阶类型,也没有对任意表达式的typeof - jcalz
3
这不是我的函数,而是库的函数。我只对我的问题答案感兴趣,即如何获取返回类型受通用参数影响的函数的返回类型。或者,如果无法做到,则需要解释为什么无法实现。如果无法实现,我有更简单的方式来解决我的用例。但如果可能的话,我更倾向于用这种方式实现。 - ed'
显示剩余2条评论
2个回答

13

虽然看起来可能不能满足您的需求,但我还是可以将其放在答案中。目前,TypeScript没有泛型值高阶类型任意表达式的typeof。在这方面,TypeScript中的泛型有点"浅"。因此,据我所知,目前不幸的是没有办法描述一个类型函数,它将类型参数插入到泛型函数中并检查结果:

// doesn't work, don't try it
type GenericReturnType<F, T> = F extends (x: T) => (infer U) ? U : never

function thinger<T>(thing: T): T {
  return thing;
}

// just {}, 
type ReturnThinger<T> = GenericReturnType<typeof thinger, T>;

所以我能为您做的就是建议解决方法。最明显的解决方法是使用类型别名来描述thinger()的返回值,然后在多个地方使用它。这是您想要的“反向”版本;而不是从函数中提取返回类型,而是从返回类型构建函数:
type ThingerReturn<T> = T; // or whatever complicated type you have

// use it here
declare function thinger<T>(thing: T): ThingerReturn<T>;

// and here
interface ThingHolder<T> {
  thing: ThingerReturn<T>;
}

// and then this works  
const myThingHolder: ThingHolder<{ a: string }> = {
  thing: thinger({ a: "lol" }),
};

这有帮助吗?我知道这不是你想要的,但希望至少为你提供了一种可能的前进方向。祝你好运!


你分享的链接中有一些有趣的阅读材料,谢谢!但是接受答案似乎是不可能的(至少需要使用TS 2.8)。 - ed'
实际上,我刚在 https://dev59.com/AlQJ5IYBdhLWcg3w2ZtT#60846777 发布了一个详细的解决方案,可能在这里也会有所帮助。 - Aidin
这里我发布了一种替代方案:https://dev59.com/71UL5IYBdhLWcg3wd3xx#64840774 - Valfar Developer
另一个相关链接跟踪此问题:https://github.com/microsoft/TypeScript/issues/37181 - Afterlame
1
@jcalz 很快就可以实现了。PR - captain-yossarian from Ukraine

1

可能这可以解决问题。但你需要创建一个假类。它之所以起作用是因为类既是类型,又是JS运行时对象。

// generic function
// we want to get its result, but we cannot do it like
// ReturnType<typeof foo<T>()> // syntax error
const foo = <T,>(arg: T) => ({ test: arg });
// so, let's create a parametric class
class Wrapper<T> {
  // with the only method that uses our "foo"
  wrapped = (arg: T) => foo(arg);   
};
// due to the fact that class is a type we can use it as a type 
// with a generic parameter.
type GetFooResult<T> = ReturnType<Wrapper<T>['wrapped']>
type Bingo = GetFooResult<number>; // { test: number }

TS Playground 链接。基于这个答案。感谢@Colin


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接