You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现保留参数类型、替换返回值类型的TypeScript wrap函数?

问题描述

希望创建一个wrap()函数,实现如下效果:

const fn = (x: string) => 'some string';

interface CustomObject {
  id: number;
  title: string;
}

const wrapped = wrap<CustomObject>(fn);

// wrapped的类型必须为: (x: string) => CustomObject

尝试过程中遇到两个问题:

问题一

以下代码无法正常工作,因为指定第一个泛型参数时,必须同时指定所有其他无默认值的泛型参数:

function wrap <Schema, Args extends any[]> (fn: (...args: Args) => any) {
  return (...args: Args): Schema => fn(...args);
}

const myFunction = (bar: string) => 'some string';

const myFunctionWrapper = wrap<{ id: number }>(myFunction);
// -----------------------------------------^: 期望2个类型参数,但仅传入1个。

问题二

如果为第二个泛型参数设置默认类型,则会丢失原函数fn的参数类型:

function wrap <Schema, Args extends any[] = any[]> (fn: (...args: Args) => any) {
  return (...args: Args): Schema => fn(...args);
}

const myFunction = (bar: string) => 'some string';

const myFunctionWrapper = wrap<{ id: number }>(myFunction);
// myFunctionWrapper的类型为: (...args: any[]) => { id: number },而非(bar: string) => { id: number }

疑问:

  • 我哪里出错了?
  • 在TypeScript中是否可以实现该需求?
问题解答

出错原因

  1. 第一种写法中,Schema和Args都是无默认值的泛型参数,TypeScript要求必须显式传入所有此类参数,只传Schema会触发类型错误。
  2. 第二种写法给Args设置了any[]默认值,当你显式指定Schema时,TypeScript会直接使用Args的默认值,跳过对原函数参数类型的推导,导致参数类型丢失。

可以实现需求,推荐两种方案

方案一:柯里化拆分调用(最直观)

通过柯里化把函数拆分为两次调用:第一次显式指定返回值类型Schema,第二次传入原函数,此时TypeScript会自动推导原函数的参数类型:

function wrap<Schema>() {
  return <F extends (...args: any[]) => any>(fn: F): 
    (...args: Parameters<F>) => Schema => {
    return (...args) => fn(...args) as Schema;
  };
}

// 使用示例
const fn = (x: string) => 'some string';
interface CustomObject { id: number; title: string; }

const wrapped = wrap<CustomObject>()(fn);
// wrapped类型为: (x: string) => CustomObject

方案二:利用TS 4.7+的泛型部分指定(更简洁)

如果你的项目使用TypeScript 4.7及以上版本,可以调整泛型参数逻辑,实现直接调用wrap<Schema>(fn)的效果:

function wrap<Schema, F extends (...args: any[]) => any>(
  fn: F
): (...args: Parameters<F>) => Schema {
  return (...args) => fn(...args) as Schema;
}

// 使用示例
const wrapped = wrap<CustomObject>(fn);
// wrapped类型为: (x: string) => CustomObject

内容的提问来源于stack exchange,提问作者localusercamp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:02:46