TypeScript中如何保留泛型参数将非流畅函数转为流畅API?
保留泛型参数的流畅API转换方案
要解决泛型函数转换为流畅API时丢失泛型参数关联的问题,你需要定义一个高阶类型来保留原函数的泛型约束和参数关联,而非直接通过infer提取参数列表(这种方式会丢失泛型上下文)。
问题根源
你原来的类型转换逻辑CreateStep["create"] extends (...arg: infer A) => any ? (...a: A) => FluentFactory : never会将泛型函数的参数“实例化”为联合类型(比如kind: "A" | "B",data: Omit<A, "kind"> | Omit<B, "kind">),丢失了kind和data之间的泛型关联关系,导致类型推断失效。
解决方案
定义一个MakeFluent高阶类型,专门用于保留原函数的泛型参数约束,同时将返回值替换为流畅接口:
// 高阶类型:保留原函数的泛型参数与约束,替换返回值为FluentFactory type MakeFluent<F> = F extends <K extends infer Constraint>(...args: infer Args) => infer _Return ? <K extends Constraint>(...args: Args) => FluentFactory : never;
然后修改FluentFactory接口,使用这个类型转换create方法:
interface FluentFactory { create: CreateStep["create"]; // 使用MakeFluent保留泛型参数关联 createFluent: MakeFluent<CreateStep["create"]>; }
完整代码示例
type A = { kind: "A"; a: string; }; type B = { kind: "B"; b: string; }; type Obj = { kind: string; }; type All = A | B; export type WithKind<T extends Obj, K extends T["kind"]> = T extends { kind: K; } ? T : never; class CreateStep { create<K extends All["kind"]>( kind: K, data: Omit<WithKind<All, K>, "kind"> ): WithKind<All, K> { return { ...data, kind } as WithKind<All, K>; } } // 高阶类型:保留原函数的泛型参数与约束,替换返回值为FluentFactory type MakeFluent<F> = F extends <K extends infer Constraint>(...args: infer Args) => infer _Return ? <K extends Constraint>(...args: Args) => FluentFactory : never; interface FluentFactory { create: CreateStep["create"]; createFluent: MakeFluent<CreateStep["create"]>; } const inst: FluentFactory = {} as FluentFactory; // 原方法正常工作 inst.create("A", { a: "a" }); // 流畅方法现在会正确关联kind与data的类型 inst.createFluent("A", { a: "a" }).createFluent("B", { b: "b" }); // 错误示例:传入不符合kind的data会触发类型检查 inst.createFluent("A", { b: "b" }); // TypeScript会报错
效果说明
createFluent现在会保留原函数的泛型参数K,以及kind: K和data: Omit<WithKind<All, K>, "kind">之间的类型关联。- 调用时TypeScript会根据传入的
kind自动推断data的必填字段,不符合的参数会触发类型错误,完全保留了原函数的类型安全。
内容的提问来源于stack exchange,提问作者nathanwinder
相关产品推荐
相关产品推荐

