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

如何为可管道类的pipe方法添加类型约束,仅允许解构已添加属性?

实现类型安全的链式Pipe字典填充类

问题描述

我有一个包含字典的类,可通过pipe链式调用特定函数填充字典:函数接收当前字典对象,解构已有属性作为参数,返回包含新属性的对象(新属性会被添加到字典中)。需要给pipe函数添加类型定义,使其仅允许解构此前已添加的属性,避免出现像示例中访问不存在属性却不报错的情况。

原示例代码(存在类型不安全问题):

type AugmentFun = (source: Record<string, any>) => Record<string, any>;

class Pipeable {
  constructor(private dict: Record<string, any>) {}

  static of = (dict: Record<string, any>) => new Pipeable(dict);
  static augment = (source: Pipeable, fun: AugmentFun) => {
    return Pipeable.of(Object.assign({}, source.dict, fun(source.dict)));
  };

  pipe = (...funs: AugmentFun[]) => funs.reduce(Pipeable.augment, this);
}

const p = new Pipeable({});

// 合法场景,不应报错
const res1 = p.pipe(
  () => ({ a: 1, b: 2 }),       // { a: 1, b: 2 }
  ({ a, b }) => ({ c: a + b }), // { a: 1, b: 2, c: 3}
  ({ c }) => ({ d: c ** 2 })    // { a: 1, b: 2, c: 3, d: 9}
);

// 非法场景,应报错但未报错
const res2 = p.pipe(
  () => ({ a: 1, b: 2 }),       // { a: 1, b: 2 }
  ({ c }) => ({ d: c + 10 })    // 错误:"c"不存在于当前字典中
);

解决方案:类型安全的实现

通过泛型跟踪字典类型和分步约束函数输入输出,可以实现严格的类型检查:

// 定义增强函数类型:输入当前字典T,返回新增属性U
type AugmentFun<T, U extends Record<string, unknown>> = (source: T) => U;

// 定义Reduce类型,用于串联多个增强函数的类型
type PipeReduce<T, Fs extends any[]> = Fs extends [
  infer First,
  ...infer Rest
]
  ? First extends AugmentFun<infer Input, infer Output>
    ? PipeReduce<Input & Output, Rest>
    : T
  : T;

class Pipeable<T extends Record<string, unknown> = {}> {
  constructor(private dict: T) {}

  static of = <U extends Record<string, unknown>>(dict: U) => new Pipeable(dict);

  static augment = <S extends Record<string, unknown>, U extends Record<string, unknown>>(
    source: Pipeable<S>,
    fun: AugmentFun<S, U>
  ): Pipeable<S & U> => {
    return Pipeable.of({ ...source.dict, ...fun(source.dict) });
  };

  pipe = <Fs extends AugmentFun<any, any>[]>(
    ...funs: Fs
  ): Pipeable<PipeReduce<T, Fs>> => {
    return funs.reduce((acc, fun) => Pipeable.augment(acc, fun), this) as Pipeable<PipeReduce<T, Fs>>;
  };
}

关键说明

  • 泛型跟踪字典类型:Pipeable<T>中的T会实时跟踪当前字典的所有属性类型,替代原本模糊的Record<string, any>
  • 增强函数类型约束:AugmentFun<T, U>明确要求函数的输入是当前的字典类型T,输出是新增的属性U,确保函数只能解构T中已存在的属性
  • PipeReduce类型串联:PipeReduce<T, Fs>会递归遍历所有pipe函数,依次将前一个函数的输出(新增属性)合并到当前字典类型中,确保后续函数只能访问之前步骤已添加的属性
  • 类型安全的augment方法:augment方法会返回合并了原属性和新增属性的Pipeable<S & U>,保证类型的正确传递

效果验证

使用上述实现后:

  • 合法的res1不会出现类型错误,且res1的类型会被推断为Pipeable<{a: number; b: number; c: number; d: number}>
  • 非法的res2中,({ c })会直接抛出类型错误:属性"c"不存在于类型"{ a: number; b: number; }"中,符合预期

内容的提问来源于stack exchange,提问作者Adam B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 09:46:05