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

TypeScript:如何从子函数向父工厂函数推导参数类型

基于子函数配置自动推导父工厂函数参数类型的TypeScript实现

要实现根据fetchClient调用时是否传入schema,自动推导createFetchClient中onError的参数类型,核心是让TypeScript关联起子函数的配置类型与父工厂函数的回调参数类型。以下是两种可行的实现方案:

方案一:利用条件类型与泛型函数

通过明确区分带/不带schema的配置类型,结合条件类型动态推导错误类型,让onError自动适配不同调用场景:

interface SchemaError {
  schemaError: any;
}

// 拆分配置类型,让TypeScript精准区分两种场景
type FetchClientConfig = 
  | { schema?: never } // 无schema的配置
  | { schema: any };   // 带schema的配置

// 根据配置类型推导对应的错误类型
type FetchError<T extends FetchClientConfig> = 
  T extends { schema: any } ? Error | SchemaError : Error;

interface CreateFetchClientConfig {
  // 泛型onError函数,根据后续调用的配置类型匹配错误参数
  onError: <T extends FetchClientConfig>(error: FetchError<T>) => any;
}

const createFetchClient = ({ onError }: CreateFetchClientConfig) => {
  // 泛型fetchClient,接收具体配置类型T
  function fetchClient<T extends FetchClientConfig>(config: T) {
    if (config.schema !== undefined) {
      // 此处onError参数自动推断为 Error | SchemaError
      onError(new Error('请求失败'));
      onError({ schemaError: '校验失败' });
    } else {
      // 此处onError参数自动推断为 Error
      onError(new Error('请求失败'));
    }
  }
  return fetchClient;
};

// 测试:调用时不带schema,onError的error类型为Error
const fetchClient1 = createFetchClient({
  onError(error) {
    console.log(error.message); // 仅能访问Error的属性
  },
});
fetchClient1({});

// 测试:调用时带schema,onError的error类型为Error | SchemaError
const fetchClient2 = createFetchClient({
  onError(error) {
    if ('schemaError' in error) {
      console.log(error.schemaError); // 访问SchemaError的属性
    } else {
      console.log(error.message); // 访问Error的属性
    }
  },
});
fetchClient2({ schema: {} });

关键说明:

  1. 拆分配置类型:将FetchClientConfig拆分为两个明确分支,避免可选属性导致的类型模糊。
  2. 条件类型推导错误:FetchError<T>根据配置类型自动返回对应的错误联合类型。
  3. 泛型onError函数:让onError能根据fetchClient的调用参数动态匹配错误类型,无需手动指定泛型。

方案二:利用函数重载

通过给返回的fetchClient定义重载签名,明确不同配置对应的错误类型:

interface SchemaError {
  schemaError: any;
}

interface CreateFetchClientConfig<E> {
  onError: (error: E) => any;
}

// 定义fetchClient的两个重载签名,对应不同配置场景
type FetchClient = {
  (config: { schema?: never }): void;
  (config: { schema: any }): void;
};

const createFetchClient = <E>({ onError }: CreateFetchClientConfig<E>) => {
  const fetchClient: FetchClient = (config: { schema?: any }) => {
    if (config.schema !== undefined) {
      onError(new Error('请求失败') as Error | SchemaError);
      onError({ schemaError: '校验失败' } as SchemaError);
    } else {
      onError(new Error('请求失败') as Error);
    }
  };
  return fetchClient;
};

// 测试:无schema调用,onError的error为Error
const fetchClient1 = createFetchClient({
  onError(error) {
    console.log(error.message);
  },
});
fetchClient1({});

// 测试:带schema调用,onError的error为Error | SchemaError
const fetchClient2 = createFetchClient({
  onError(error) {
    if ('schemaError' in error) {
      console.log(error.schemaError);
    } else {
      console.log(error.message);
    }
  },
});
fetchClient2({ schema: {} });

关键说明:

  • 重载签名:通过给FetchClient定义两个重载,明确告知TypeScript不同配置对应的函数行为。
  • 类型断言:在函数内部调用onError时,需要用类型断言明确错误类型,配合重载实现类型推导。

内容的提问来源于stack exchange,提问作者L.Blondy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 18:03:30