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

TypeScript中如何用函数复刻类的implements功能并兼容Jest Mock?

解决TypeScript中函数返回接口实现时丢失Jest Mock类型的问题

先明确你的场景:给定接口

interface Foo {
  a: () => string
}

用类实现时,TypeScript既能保证类符合接口要求,又能识别a是jest.Mock类型,调用mockImplementation完全没问题——不过注意原代码里的类写法有个小错误,a应该用等号赋值,而非冒号(冒号是类型声明,不会给属性赋值):

class Bar implements Foo {
  a = jest.fn(() => 'hello');
}

const bar = new Bar();
bar.a.mockImplementation(() => 'b') // 无类型错误

但用工厂函数实现时,返回的对象被接口Foo约束后,a的类型被收窄成() => string,导致无法调用Mock的专属方法:

function newFoo (): Foo {
  return {
    a: jest.fn(() => 'a')
  }
}

const foo = newFoo();
foo.a.mockImplementation(() => 'b') // 报错:mockImplementation不存在于()=>string类型

核心原因

类中直接给a赋值为jest.fn(),TypeScript会自动推断a的类型是jest.Mock<string, []>,而这个类型天然兼容Foo接口里的() => string,所以既能通过接口校验,又能保留Mock的类型信息。但工厂函数因为明确指定返回类型为Foo,TypeScript会强制把返回对象的类型收窄到接口定义,丢失了Mock的额外方法类型。

解决方案

方案1:临时类型断言(简单直接)

在调用Mock方法时,把foo.a断言为jest.Mock:

const foo = newFoo();
(foo.a as jest.Mock).mockImplementation(() => 'b')

优点是改动小,缺点是每次调用Mock方法都要写断言,略显繁琐。

方案2:返回交叉类型(兼顾约束与类型保留)

让工厂函数返回Foo与Mock类型的交叉类型,既保证符合接口要求,又能识别Mock的方法:

function newFoo(): Foo & { a: jest.Mock<string, []> } {
  return {
    a: jest.fn(() => 'a')
  }
}

const foo = newFoo();
foo.a.mockImplementation(() => 'b') // 无类型错误

方案3:用satisfies关键字自动推导(最优雅,TS 4.9+支持)

去掉函数的返回类型声明,让TypeScript自动推导返回对象的类型,同时用satisfies确保对象符合Foo接口:

function newFoo() {
  return {
    a: jest.fn(() => 'a')
  } satisfies Foo;
}

const foo = newFoo();
foo.a.mockImplementation(() => 'b') // 无类型错误

这个方案既保证了返回对象的接口合规性,又完整保留了Mock的类型信息,不用手动维护额外类型。

关于你的背景需求

你提到选择工厂函数是因为闭包封装性更好、类的私有属性会被Object.keys()识别、第三方库会对意外属性报错——以上方案都不会给对象添加可枚举的额外属性,Jest Mock的方法都是不可枚举的,完全符合你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 01:15:52