使用Node原生test模块Mock时如何指定重载类型
使用Node.js原生
node:test Mock重载函数时的类型匹配问题 我用Node.js原生node:test的mock库来Mock Nest.js的NestFactory.create重载函数,代码如下:
import { LoggerService } from "@nestjs/common"; import { NestFactory } from "@nestjs/core"; import { equal } from "node:assert/strict"; import { suite, test } from "node:test"; suite("Example", async () => { test("How to type the override", async ({ mock }) => { const create = mock.method(NestFactory, "create", async () => ({})); equal( create.mock.calls[0].arguments[1].logger instanceof LoggerService, true, ); }) })
create存在两个重载定义:
create<T extends INestApplication = INestApplication>(module: IEntryNestModule, options?: NestApplicationOptions): Promise<T>; create<T extends INestApplication = INestApplication>(module: IEntryNestModule, httpAdapter: AbstractHttpAdapter, options?: NestApplicationOptions): Promise<T>;
实际调用的是第一个重载(传入带logger属性的options对象),但TypeScript默认将create.mock.calls[0].arguments[1]的类型匹配为最后一个重载的AbstractHttpAdapter,导致报错:
Property 'logger' does not exist on type 'AbstractHttpAdapter<any, any, any>'.ts(2339)
已知可通过类型断言解决,但想了解是否有利用mock函数泛型的替代方案。
解决方案:给mock.method指定泛型匹配目标重载
可以通过给mock.method显式传入泛型参数,指定你实际使用的重载函数类型,让TypeScript正确推断调用参数的类型。
方式1:直接指定重载函数签名
import { LoggerService } from "@nestjs/common"; import { NestFactory, type NestApplicationOptions, type IEntryNestModule, type INestApplication } from "@nestjs/core"; import { equal } from "node:assert/strict"; import { suite, test } from "node:test"; suite("Example", async () => { test("How to type the override", async ({ mock }) => { // 显式指定泛型为第一个重载的函数类型 const create = mock.method< (module: IEntryNestModule, options?: NestApplicationOptions) => Promise<INestApplication> >(NestFactory, "create", async () => ({})); // 此时arguments[1]会被正确推断为NestApplicationOptions | undefined equal( create.mock.calls[0].arguments[1]?.logger instanceof LoggerService, true, ); }) })
方式2:提取重载类型别名简化写法
如果不想重复写函数签名,可以先从typeof NestFactory.create中提取第一个重载的类型:
import { LoggerService } from "@nestjs/common"; import { NestFactory, type NestApplicationOptions, type IEntryNestModule, type INestApplication } from "@nestjs/core"; import { equal } from "node:assert/strict"; import { suite, test } from "node:test"; // 从create的重载中提取第一个签名的类型 type CreateFirstOverload = typeof NestFactory.create extends { (module: IEntryNestModule, options?: NestApplicationOptions): Promise<INestApplication>; (...args: any[]): any; } ? (module: IEntryNestModule, options?: NestApplicationOptions) => Promise<INestApplication> : never; suite("Example", async () => { test("How to type the override", async ({ mock }) => { // 使用预定义的类型别名作为泛型 const create = mock.method<CreateFirstOverload>(NestFactory, "create", async () => ({})); equal( create.mock.calls[0].arguments[1]?.logger instanceof LoggerService, true, ); }) })
原理是mock.method的泛型参数允许你指定被Mock函数的具体类型签名,TypeScript会基于你指定的重载来推断Mock调用的参数类型,而非默认使用最后一个重载。
内容的提问来源于stack exchange,提问作者myol
相关产品推荐
相关产品推荐

