32.7 Type-Level Testing with tsd and expect-type

Right, so you’ve got your unit tests passing. Your functions are returning the right values. But are they returning the right types? Are you sure? In a language like TypeScript, a function can pass all its runtime tests with flying colors and still be a type-level catastrophe waiting to happen. This is where type-level testing comes in. It’s like putting a second, even more pedantic security guard at the door of your codebase—one who only cares about the IDs and not the person.

32.6 Testing Generic Functions and Complex Types

Alright, let’s talk about testing the stuff that makes TypeScript, well, TypeScript: generics and complex types. If you’re testing a function that adds two numbers, you don’t need me. But when you have a function that can juggle string[], Promise<number>, or a Map<CustomerId, Partial<Invoice>> without breaking a sweat, your tests need to be just as clever. The good news? It’s not as scary as it looks. The bad news? You can’t just rely on type checking at compile time; you have to verify the behavior at runtime. That’s where we roll up our sleeves.

32.5 Typing Mocked Functions: jest.MockedFunction and vi.Mocked

Alright, let’s talk about mocking in TypeScript. It’s the part of testing where we all collectively agree to pretend things are working so we can test other things in isolation. It’s a necessary lie, and like any good lie, it needs to be well-constructed to be believable. TypeScript, being the wonderfully pedantic friend that it is, will immediately call you out on your flimsy, untyped mocks. That’s where jest.MockedFunction and its Vitest cousin vi.Mocked come in—they’re your tools for building air-tight, convincing lies that keep both your tests and the type checker happy.

32.4 Mocking Modules: jest.mock and vi.mock with Types

Alright, let’s talk about mocking. It’s the part of testing everyone loves to hate, but mastering it is what separates you from the amateurs. We mock things for one simple reason: isolation. We want to test our code, not the entire universe of dependencies it happens to call. Your function that processes a user shouldn’t fail because the fetchUser API call decided to take a nap. We replace that real, flaky, or just plain slow module with a predictable stand-in—a mock.

32.3 Typing Test Fixtures and Factories

Right, let’s talk about the part of testing that everyone loves to hate: setting up data. You’re not here to test your ability to manually craft a User object with seventeen nested properties for the fiftieth time. You’re here to test logic. So we use fixtures and factories. And since we’re in TypeScript, we’re going to do it with types, because we’re not animals. The core problem is simple: your functions expect well-typed arguments, but in your tests, you often only care about a subset of those properties. You need a way to generate complete, valid-looking objects without specifying every single field every single time. Doing it manually is a recipe for brittle, unreadable tests that shatter the moment your main data model changes.

32.2 Vitest: Zero-Config TypeScript Testing

Alright, let’s talk about Vitest. If you’ve ever felt the cold, bureaucratic weight of configuring Jest for TypeScript—the ts-jest or babel-jest rigmarole, the type-checking that’s either slow or non-existent—then Vitest is your liberation. It’s the test runner that looks at the existing, brilliant tooling of the Vite ecosystem and says, “Yeah, I’ll just use that, thanks.” It’s the zero-config dream that actually delivers, and it’s so fast it feels like it’s cheating. Which, in a good way, it is.

32.1 Configuring Jest with ts-jest or Babel for TypeScript

Right, let’s get your TypeScript playing nicely with Jest. This is one of those things that feels like it should be a one-line setup, but the reality is, we have to make a few choices. The core problem is simple: Jest is a JavaScript testing framework. It expects .js files. You’re giving it .ts files. It looks at you like you’ve just handed it a fish and asked it to do your taxes.

— joke —

...