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

从Jest迁移到Vitest时vi.importActual返回unknown类型的问题

问题解析与解决

一、Jest与Vitest类型差异的原因

  • Jest的jest.requireActual类型定义直接返回any:@types/jest中把这个方法的返回值设为any,所以即使你开启noImplicitAny: true,TS也不会对any类型的变量触发属性访问报错——因为any会绕过几乎所有类型检查。
  • Vitest的vi.importActual遵循ES模块规范:它本质是封装了ES的动态import(),而动态import()的返回类型是Promise<unknown>。Vitest的类型定义没有像Jest那样放宽到any,而是严格遵循TS对动态导入的类型规则,所以返回的Promise解析后是unknown类型。

二、TypeScript的推断逻辑

当你访问myLib.things时,TS确实能通过后续代码(比如things的使用场景)反向推断出Thing[]类型,但这是窄化推断,前提是你已经合法地访问了属性。而unknown类型的核心约束是:必须先通过类型断言、类型守卫等方式确认其具体类型,才能访问它的属性或方法——这就是为什么即使TS能推断出things的类型,访问myLib.things时依然会触发TS18046错误。

而Jest中的any类型没有这个约束,TS会完全信任你对any类型的所有操作,不会做任何检查,所以即使开启noImplicitAny也不会报错(noImplicitAny主要约束的是那些无法推断类型的变量声明,而jest.requireActual明确返回any,不属于隐式any的范畴)。

三、解决方法

1. 给vi.importActual指定泛型

直接通过泛型指定导入模块的类型,这是最简洁的方式:

const myLib = await vi.importActual<typeof import('myLib.js')>('myLib.js');

2. 使用类型断言

如果泛型写法觉得繁琐,也可以用类型断言直接指定类型:

const myLib = await vi.importActual('myLib.js') as typeof import('myLib.js');

3. 配合类型守卫(适合复杂场景)

如果需要更严谨的类型检查,可以用类型守卫先确认myLib的结构:

const myLib = await vi.importActual('myLib.js');

function isMyLib(obj: unknown): obj is typeof import('myLib.js') {
  return typeof obj === 'object' && obj !== null && 'things' in obj;
}

if (isMyLib(myLib)) {
  // 这里访问myLib.things不会报错
  console.log(myLib.things);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:47:53