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

TypeScript通用工厂类型报错:createFeature函数类型定义问题

TypeScript简单工厂类型定义问题解决

问题背景

实现了一个简单工厂模式,但主函数createFeature处出现类型错误,需要修正类型定义。

代码示例

interface Feature {
    id: string;
    kind: string;
}

export function create<Kind extends string, Fields extends Record<any, any>>(
  kind: Kind,
  options: Fields,
): Feature & { kind: Kind } & Fields {
  return {
    id: '',
    kind,
    ...options,
  };
}

interface PointOptions {
    coordinate: [number, number];
}

interface Point extends Feature {
    x: number;
    y: number;
}

function createPoint({ coordinate: [x, y] }: PointOptions): Point {
    return create('point', { x, y });
}

interface LineOptions {
    waypoints: [number, number][];
}

interface Line extends Feature {
    coordinates: { x: number; y: number }[];
}

function createLine(options: LineOptions): Line {
    return create('line', {
        coordinates: options.waypoints.map(([x, y]) => ({ x, y })),
    });
}

const features = {
    point: createPoint,
    line: createLine,
} as const;

type Library = typeof features;
export type FeatureKey = keyof Library;
export type FeatureOptions<Type extends FeatureKey> = Library[Type] extends (
  options: infer Options,
) => any
  ? Options
  : never;
export type FeatureReturn<Type extends FeatureKey> = Library[Type] extends (
  options: any,
) => infer ConcreteFeature
  ? ConcreteFeature
  : never;

function createFeature<Type extends FeatureKey>(
  type: Type,
  options: FeatureOptions<Type>,
): FeatureReturn<Type> {
  if (!(type in features)) {
    throw new Error('Unknown feature type');
  }
  return features[type](options);
}

报错信息

Type 'Point | Line' is not assignable to type 'FeatureReturn<Type>'.
  Type 'Point' is not assignable to type 'FeatureReturn<Type>'.

Argument of type 'FeatureOptions<Type>' is not assignable to parameter of type 'PointOptions & LineOptions'.
  Type 'unknown' is not assignable to type 'PointOptions & LineOptions'.
    Type 'unknown' is not assignable to type 'PointOptions'.
      Type 'FeatureOptions<Type>' is not assignable to type 'PointOptions'.
        Type 'unknown' is not assignable to type 'PointOptions'.

问题原因

当使用泛型Type extends FeatureKey时,TypeScript无法将type的具体值与options、返回值的类型做精确绑定。features[type]的类型是联合类型typeof createPoint | typeof createLine,调用该联合类型函数时,TypeScript会要求参数是所有函数参数的交集(即PointOptions & LineOptions,这显然不符合业务逻辑),返回值则是Point | Line,无法匹配FeatureReturn<Type>的具体类型。

解决方案

方案1:函数重载(最直观)

为每个Feature类型定义重载签名,明确参数与返回值的对应关系:

// 重载签名,明确每种类型的参数和返回值
function createFeature(type: 'point', options: PointOptions): Point;
function createFeature(type: 'line', options: LineOptions): Line;

// 实现签名
function createFeature(type: FeatureKey, options: FeatureOptions<FeatureKey>) {
  if (!(type in features)) {
    throw new Error('Unknown feature type');
  }
  return features[type](options as any);
}

方案2:泛型+类型断言(保留灵活性)

若需保留泛型的扩展能力,可通过类型断言告知TypeScript参数与返回值的正确性:

function createFeature<Type extends FeatureKey>(
  type: Type,
  options: FeatureOptions<Type>,
): FeatureReturn<Type> {
  if (!(type in features)) {
    throw new Error('Unknown feature type');
  }
  // 断言参数匹配当前类型的函数参数,返回值匹配对应Feature类型
  return features[type](options as Parameters<Library[Type]>[0]) as FeatureReturn<Type>;
}

方案3:重构类型映射(优雅扩展)

定义完整的Feature类型映射,让TypeScript自动推导关联类型:

// 定义Feature类型映射,统一管理每种类型的参数和返回值
type FeatureMap = {
  point: {
    Options: PointOptions;
    Type: Point;
  };
  line: {
    Options: LineOptions;
    Type: Line;
  };
};

// 基于映射推导全局类型
export type FeatureKey = keyof FeatureMap;
export type FeatureOptions<Type extends FeatureKey> = FeatureMap[Type]['Options'];
export type FeatureReturn<Type extends FeatureKey> = FeatureMap[Type]['Type'];

// 保持原features对象不变
const features = {
  point: createPoint,
  line: createLine,
} as const;

function createFeature<Type extends FeatureKey>(
  type: Type,
  options: FeatureOptions<Type>,
): FeatureReturn<Type> {
  if (!(type in features)) {
    throw new Error('Unknown feature type');
  }
  return features[type](options as any) as FeatureReturn<Type>;
}

验证

修改后,调用createFeature('point', { coordinate: [1, 2] })会自动推断返回Point类型,调用createFeature('line', { waypoints: [[1,2],[3,4]] })会自动推断返回Line类型,且无类型错误。

内容的提问来源于stack exchange,提问作者Vitaliy Leonov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 15:14:56