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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 07:28:15