如何为TypeScript调度函数实现返回类型自动推断?
实现带自动类型推断的Dispatch函数
要让TypeScript根据传入的type自动推断args类型和返回值类型,核心是利用泛型+映射类型,基于commandsOrQueries的具体类型自动推导关联关系,而非手动维护联合类型。
解决方案步骤
1. 锁定命令/查询对象的类型
给commandsOrQueries添加as const,让TypeScript保留其键和值的具体类型(避免被宽泛的Record<string, Function>覆盖):
const commandsOrQueries = { CREATE_USER_WITH_PASSWORD: CreateUserCommandHandler, GET_USERS: GetUsersQueryHandler, GET_USER_PROFILE: GetUserProfileQueryHandler } as const;
2. 定义辅助类型
通过TypeScript内置工具类型(Parameters/ReturnType)自动提取类型信息:
// 提取所有命令/查询的类型键 type CommandOrQueryType = keyof typeof commandsOrQueries; // 根据类型键获取对应的处理函数类型 type Handler<T extends CommandOrQueryType> = typeof commandsOrQueries[T]; // 获取处理函数的参数类型 type HandlerArgs<T extends CommandOrQueryType> = Parameters<Handler<T>>[0]; // 获取处理函数的返回类型 type HandlerReturn<T extends CommandOrQueryType> = ReturnType<Handler<T>>;
3. 定义Dispatch函数的参数类型
用泛型关联type和arg的类型,确保两者严格对应:
type DispatchParams<T extends CommandOrQueryType> = { type: T; arg: HandlerArgs<T>; };
4. 实现Dispatch函数
通过泛型让TypeScript自动推断返回值类型:
export async function dispatch<T extends CommandOrQueryType>({ type, arg }: DispatchParams<T>): Promise<HandlerReturn<T>> { return commandsOrQueries[type](arg); }
完整的mediator.ts代码
import { CreateUserCommandHandler, CreateUserCommand } from "./bounded_contexts/CreateUserWithPasswordCommand"; import { GetUsersQueryHandler, GetUsersQuery } from "./bounded_contexts/GetUsersQuery"; import { GetUserProfileQueryHandler, GetUserProfileQuery } from "./bounded_contexts/GetUserProfileQuery"; const commandsOrQueries = { CREATE_USER_WITH_PASSWORD: CreateUserCommandHandler, GET_USERS: GetUsersQueryHandler, GET_USER_PROFILE: GetUserProfileQueryHandler } as const; type CommandOrQueryType = keyof typeof commandsOrQueries; type Handler<T extends CommandOrQueryType> = typeof commandsOrQueries[T]; type HandlerArgs<T extends CommandOrQueryType> = Parameters<Handler<T>>[0]; type HandlerReturn<T extends CommandOrQueryType> = ReturnType<Handler<T>>; type DispatchParams<T extends CommandOrQueryType> = { type: T; arg: HandlerArgs<T>; }; export async function dispatch<T extends CommandOrQueryType>({ type, arg }: DispatchParams<T>): Promise<HandlerReturn<T>> { return commandsOrQueries[type](arg); }
效果验证
在index.ts中调用时,TypeScript会自动完成精确的类型推断:
(async () => { // result自动推断为boolean const result = await dispatch({ type: "CREATE_USER_WITH_PASSWORD", arg: { email: "theemail@mail.com", password: "the password" } }); // result2自动推断为{ users: { id: string; name: string }[] } const result2 = await dispatch({ type: "GET_USERS", arg: {} }); // result3自动推断为{ firstName: string; lastName: string; dateOfBirth: Date } const result3 = await dispatch({ type: "GET_USER_PROFILE", arg: { userId: "the user Id" } }); })();
为什么之前的方法无法自动推断返回类型
之前手动维护的Mediator联合类型,仅能约束type和arg的对应关系,但Dispatch函数的返回类型会被推断为所有处理函数返回值的联合类型,TypeScript无法根据传入的具体type精确缩小范围。而通过泛型绑定type与返回类型后,每个调用都会对应唯一的返回类型,从而实现自动推断。
内容的提问来源于stack exchange,提问作者Jose A
相关产品推荐
相关产品推荐

