如下面的代码所示.我有一个compose函数,它接收一个泛型函数fn,函数fn的参数想要获得fn的返回类型,并返回它.但遇到错误:Type 'F' is not generic.

enter image description here

代码和playground

function compose<F extends <T>(val: T) => any, A>(fn: F, val: A): ReturnType<F<A>> {
    return fn(val)
}

interface FooReturn<T> {
    foo: T
}
function foo<T>(val: T): FooReturn<T> {
    return {
        foo: val
    }
}

interface BarReturn<T> {
    bar: T
}
function bar<T>(val: T): BarReturn<T> {
    return {
        bar: val
    }
}

let fooRes = compose(foo, '') // expect FooReturn<string>
let barRes = compose(bar, 1) // expect BarReturn<number>

typescript playground

期待

这可以实现吗?

推荐答案

遗憾的是,TypeScrip缺乏对instantiatingspecifying的直接支持,即在类型级别对generic函数的类型参数.对此至少有一个开放的特性请求;请参阅microsoft/TypeScript#44521,但到目前为止它还没有实现.请注意,TypeScrip 4.7引入了对instantiation expressions的支持,这允许您在不调用泛型函数value的情况下为其指定类型参数,但没有类似的方法可以纯粹在类型级别上这样做.因为F只是一个函数类型,而不是函数值,所以您不能执行类似F<A>的操作.

请注意,语法F<A>将是不明确的,因为不清楚A是否应该是泛型call signature的类型参数(您在这里所要求的),或者它是否应该是泛型type的类型参数(通常被认为是这样).事实上,由于F本身是通用的,这两项工作都不是...Typescript 也缺少microsoft/TypeScript#1213分所要求的higher kinded types分.因此,无论如何,F<A>在TS5.1的Typescript 中是根本不可能的.


正如前面提到的,TypeScrip对泛型类型或泛型函数类型的任意操作没有太多直接支持.在一些特定情况下,您可以获得一些高阶行为,但它们本质上是硬编码的启发式特性,并不是所有地方都完全支持它们.实例化表达式曾经是这样的功能.

还有higher order type inference from generic functions个.这实际上可以用来使您的示例代码工作:

function compose<A, R>(fn: (a: A) => R, val: A): R {
    return fn(val)
}

interface FooReturn<T> { foo: T }
function foo<T>(val: T): FooReturn<T> {
    return { foo: val }
}
let fooRes = compose(foo, '') 
// let fooRes: FooReturn<string>

interface BarReturn<T> { bar: T }
function bar<T>(val: T): BarReturn<T> {
    return { bar: val }
}    
let barRes = compose(bar, 1) 
// let barRes: BarReturn<number>

但它很脆弱;您必须将泛型函数直接传递给compose().不能使用泛型方法或泛型函数的任何其他更复杂的嵌套来传递对象.这被认为是打印脚本的设计限制,如第microsoft/TypeScript#49505条所述.因此,尽管这种情况的某些情况可以得到充分处理,但总体问题仍然没有得到解决.

Playground link to code

Typescript相关问答推荐

Angular 17 Select 错误core.mjs:6531错误错误:NG 05105:发现意外合成监听器@transformPanel.done

即使子网是公共的,AWS CDK EventBridge ECS任务也无法分配公共IP地址

角形标题大小写所有单词除外

我们过go 不能从TypeScript中的联合中同时访问所有属性?

在键和值为ARGS的泛型函数中未正确推断类型

如何使用泛型自动推断TS中的类型

TypeScrip表示该类型不可赋值

ANGLE找不到辅助‘路由出口’的路由路径

是否使用非显式名称隔离在对象属性上声明的接口的内部类型?

如何从扩展接口推断泛型?

使用Redux Saga操作通道对操作进行排序不起作用

TypeError:正文不可用-NextJS服务器操作POST

如何将别名添加到vitest配置文件?

为什么我的动画状态在组件实例之间共享?

TypeScrip:使用Cypress测试包含插槽的Vue3组件

TS不能自己推断函数返回类型

TypeScript:如何使用泛型和子类型创建泛型默认函数?

TypeScript:方法获胜';t接受较窄类型作为参数

为什么我的 Typescript 函数中缺少 void 隐式返回类型?

Mongodb TypeError:类继承 events_1.EventEmitter 不是对象或 null