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

使用TypeScript创建类型安全的Fake对象

问题:基于TypeScript类型自动生成Fake实例是否需要Babel预处理?

需求场景

假设定义如下TypeScript类型:

type Foo = { id: string, foo: () => string }

希望创建一个Fake实例,自动为类型中的属性生成符合类型的默认值:

const foo = new Fake<Foo>()
foo.id // 返回空字符串 ""
foo.foo() // 返回空字符串 ""

这种能力在测试中模拟第三方依赖时非常实用,核心难点是仅通过TypeScript类型信息生成有效的JavaScript代码。

当前非类型安全的Fake实现

以下是一个初步实现,但缺乏类型安全性:

export class Fake {
  constructor({
    props = {},
    didCallMethod = () => {},
  }: {
    props?: Record<string, any>
    didCallMethod?: (name: string, args: any[]) => void
  } = {}) {
    return new Proxy<any>({}, {
      get: (target, prop) => {
        if (prop in props) {
          // @ts-expect-error
          return props[prop]
        }

        if (prop in target) {
          return target[prop]
        }
        return (...args: any[]) => {
          return didCallMethod(String(prop), args)
        }
      },
    })
  }
}

解答:不需要Babel预处理

TypeScript的类型信息仅存在于编译阶段,最终会被擦除为纯JavaScript代码。要实现类型安全的Fake,核心是利用TypeScript的泛型、条件类型、索引类型等特性约束代码行为,完全不需要依赖Babel这类语法转换工具。

类型安全的Fake实现示例

可以通过泛型约束和类型推导,让Fake类严格遵循传入的类型定义:

// 推导属性的返回类型:如果是函数则取其返回值,否则取属性本身类型
type FakeReturnType<T> = T extends () => infer R ? R : T;

export class Fake<T> {
  constructor({
    // 约束props必须符合T的部分属性类型
    props = {} as Partial<{ [K in keyof T]: FakeReturnType<T[K]> }>,
    // 约束回调函数的参数和返回值类型
    didCallMethod = () => "" as FakeReturnType<T[keyof T]>,
  }: {
    props?: Partial<{ [K in keyof T]: FakeReturnType<T[K]> }>;
    didCallMethod?: (name: keyof T, args: any[]) => FakeReturnType<T[keyof T]>;
  } = {}) {
    return new Proxy({} as T, {
      get: (target, prop: keyof T) => {
        // 优先返回自定义props中的值
        if (prop in props) {
          const value = props[prop];
          // 如果是函数,包装后调用didCallMethod
          if (typeof value === 'function') {
            return (...args: any[]) => {
              didCallMethod(prop, args);
              return value(...args);
            };
          }
          return value;
        }

        // 返回目标对象本身已有的属性
        if (prop in target) {
          return (target as any)[prop];
        }

        // 根据类型生成默认值
        const propType = typeof ({} as T)[prop];
        if (propType === 'function') {
          return (...args: any[]) => didCallMethod(prop, args);
        } else {
          // 针对不同基础类型返回对应默认值
          switch (propType) {
            case 'string':
              return "";
            case 'number':
              return 0;
            case 'boolean':
              return false;
            default:
              return null;
          }
        }
      },
    });
  }
}

实现说明

  • 用泛型T约束整个Fake类的属性结构,确保访问的属性都属于T的键集合。
  • 通过Partial<{ [K in keyof T]: ... }>约束props参数的类型,避免传入不符合T的属性。
  • 利用条件类型FakeReturnType区分函数和非函数属性,确保回调函数的返回值符合类型要求。
  • 最终编译后的JavaScript代码是纯ES Proxy实现,不需要任何Babel插件或预处理步骤。

Babel的核心作用是语法降级(如将ES6+代码转换为ES5兼容代码),而这里的需求是利用TypeScript的类型系统实现类型安全的模拟,和Babel没有关联,完全不需要额外的Babel预处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 17:35:14