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

TypeScript:如何从联合类型动态提取函数泛型并生成foo函数?

问题描述

我们定义了如下TypeScript类型与工具函数:

type FooParams <Params extends unknown[], Result> = { 
 name: string, 
 request: (...params: Params) => Promise<Result> 
}

const foo = <Params extends unknown[], Result>(params: FooParams<Params, Result>) => {
  // 内部逻辑
}

同时有Todo接口、请求函数及存储请求的requestStore:

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

const getTodos: () => Promise<Todo[]> = () => Promise.resolve([{ id: 2, title: 'clean' }]);

const getTodo: (id: number) => Promise<Todo> = (id: number) => Promise.resolve({ id, title: 'clean' });

const requestStore = {
  getTodo: {
    name: 'getTodo',
    request: getTodo,
  },
  getTodos: {
    name: 'getTodos',
    request: getTodos,
  },
} as const;

手动调用foo(requestStore['getTodo'])可以正常工作,但通过以下动态方式创建对应foo函数时会出现类型错误:

// 报错信息:
// Type '(() => Promise<Todo[]>) | ((id: number) => Promise<Todo>)' is not assignable to type '() => Promise<Todo[]>'.
//  Type '(id: number) => Promise<Todo>' is not assignable to type '() => Promise<Todo[]>'.(2322)
const createFooFromStore = (requestName: keyof typeof requestStore) => () => {
  const { name, request } = requestStore[requestName]
  foo({ name, request })
}

需要修改代码,为requestStore中的每个条目正确生成对应的foo函数。

问题原因

当requestName为keyof typeof requestStore时,requestStore[requestName]的类型是两个请求对象的联合类型,此时request的类型是两个函数的联合类型。而foo要求传入的是具体某一个函数类型,而非联合类型,因此TypeScript的类型检查会失败。

解决方案

方案1:泛型约束实现类型收窄

将createFooFromStore定义为泛型函数,让TypeScript跟踪具体的键类型,从而正确推断对应请求的类型:

const createFooFromStore = <K extends keyof typeof requestStore>(requestName: K) => () => {
  const { name, request } = requestStore[requestName];
  foo({ name, request }); // 类型推断正常
};

方案2:预先生成全量foo函数对象

如果需要一次性为所有请求生成对应foo函数,可以创建映射对象,利用TypeScript的映射类型自动推导:

type FooStore = {
  [K in keyof typeof requestStore]: () => void;
};

const fooStore: FooStore = Object.fromEntries(
  Object.entries(requestStore).map(([key, value]) => [
    key,
    () => foo(value)
  ])
) as FooStore;

// 使用示例
fooStore.getTodo();
fooStore.getTodos();

两种方案都能让TypeScript正确识别每个请求的具体类型,避免联合类型导致的类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 21:35:14