TypeScript
Completed
-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
217: Configuring Vitest with TypeScript
Alright, let's get Vitest wired up to our TypeScript project. I've already got a small utility library here—a CartCalculator that handles taxes and discounts—and I want to make sure the math is solid before I ship it. You'd think since Vitest is built on Vite, it would just "work" with TypeScript, and for the most part, it does. But if we just dive in without a plan, the developer experience is usually a bit clunky.
// src/cart.ts
export interface Item {
price: number;
quantity: number;
}
export function calculateTotal(items: Item[], taxRate: number): number {
const subtotal = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
return subtotal + subtotal * taxRate;
}
Just throwing it at the wall
I'll start by installing Vitest and writing a quick test. I'm not going to touch any config files yet; I just want to see if the runner can pick up the TS files. I'll create src/cart.test.ts:
// src/cart.test.ts
import { describe, it, expect } from 'vitest';
import { calculateTotal } from './cart';
describe('calculateTotal', () => {
it('should apply tax correctly', () => {
const items = [{ price: 10, quantity: 2 }];
expect(calculateTotal(items, 0.1)).toBe(22);
});
});
I run npx vitest. It works! The test passes. But look at my editor. I'm seeing red squiggles under describe and it. Now, I explicitly imported them from 'vitest', so why is TypeScript complaining? Actually, in this specific case, it isn't—but if I were to remove those imports to keep the test file cleaner, the whole thing falls apart. Most of us prefer the "global" style for tests so we aren't importing the same five functions in every single file.
The "Cannot find name 'describe'" headache
Let's try to use globals. I'll remove the import { describe, it, expect } from 'vitest' line. Immediately, TypeScript screams at me: Cannot find name 'describe'. Vitest provides these globals, but TypeScript has no idea they exist in the global namespace. It doesn't just "know" because the library is installed.
I could just ignore it, but that defeats the purpose of using TypeScript. I'll head over to tsconfig.json. I need to tell the compiler that Vitest's types should be available everywhere.
// tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"types": ["vitest/globals"] // Add this line
}
}
The squiggles vanish. Great. But wait—when I run npx vitest again, the tests fail. Why? Because I told TypeScript that the globals exist, but I haven't told Vitest to actually provide them at runtime. I've basically lied to the compiler.
Making it official with a config file
This is where we actually need a configuration file. Vitest looks for vitest.config.ts (or vite.config.ts). I'll create one in the root. I need to enable the globals flag so that describe and it are actually injected into the environment.
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true,
// I'll add this while I'm here—it helps with debugging
environment: 'node',
},
});
Now, when I run the tests, they pass, and my editor is happy. I've synced the runtime (the config file) with the type system (the tsconfig).
A quick note on the "Vite" overlap
You might notice I imported defineConfig from 'vitest/config' instead of just 'vite'. If you're building a frontend app with Vite, you can actually put your test config right inside your vite.config.ts. But for a library or a backend project, keeping it separate in vitest.config.ts is much cleaner. It prevents your production build config from being cluttered with test-only settings.
So, the workflow is: Install → Config file (runtime) → tsconfig (types). If you miss one, you're either fighting your editor or fighting the test runner.
📋 Practical Task
Fixing the UserPermission Guard Test Setup
You've been handed a project with a UserPermission guard that checks if a user has a specific role. The code is written in TypeScript, and Vitest is installed, but the project is in a "broken" state: the tests are failing to run because of missing globals, and the IDE is full of TypeScript errors regarding the test functions.
The Code:
// src/permissions.ts
export function hasPermission(userRole: string, requiredRole: string): boolean {
return userRole === requiredRole || userRole === 'admin';
}
// src/permissions.test.ts
describe('hasPermission', () => {
it('should return true if user is admin', () => {
expect(hasPermission('admin', 'editor')).toBe(true);
});
it('should return false if roles do not match', () => {
expect(hasPermission('viewer', 'editor')).toBe(false);
});
});
Your Task:
- Create a
vitest.config.tsfile that enables global test functions. - Update the
tsconfig.jsonto ensure TypeScript recognizes the Vitest globals, eliminating the "Cannot find name" errors. - Ensure the tests can be executed via
npx vitestwithout needing to manually importdescribe,it, orexpectin the test file.
There are no comments for now.