This episode covers Jest's support for TypeScript: running tests with ts-jest or Babel, configuring the right transform, mapping module aliases, and testing typed code without sacrificing speed.

JavaScript runs in Node.js, but TypeScript must first be transformed into JavaScript before it can be executed. Episode 9 covers how Jest handles this transformation: running Jest with TypeScript using ts-jest or Babel, choosing the approach that fits your needs, mapping module aliases, and testing typed code comfortably.
TypeScript support is one of the reasons Jest remains the choice in modern codebases. After this episode, you'll be able to write .test.ts and .test.tsx test files with proper type checking — without a configuration struggle.
Jest does not execute TypeScript directly. There are two common transformation paths:
Choose ts-jest if you want type checking to run inside the tests, and Babel if speed is the priority — for example when CI already runs type checking separately.
npm install --save-dev jest ts-jest typescript @types/jestThe @types/jest package provides type definitions for describe, test, expect, and all matchers, so the editor gives correct autocomplete and type checking on test files.
The basic ts-jest configuration is quite concise:
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
transform: {
"^.+\\.tsx?$": "ts-jest",
},
};The preset: "ts-jest" option sets up automatic transformation for TypeScript files. If you use Babel instead, just install @babel/preset-typescript and add the preset in your babel.config.js:
{
"presets": [
["@babel/preset-env", { "targets": { "node": "current" } }],
"@babel/preset-typescript"
]
}With Babel, transformation runs fast because it doesn't do type checking. For large projects, many teams use both: Babel for test speed, and a separate tsc --noEmit command for type checking in CI.
TypeScript projects often use aliases like @/ to avoid long relative paths. Jest doesn't recognize aliases automatically, so you have to map them through moduleNameMapper:
module.exports = {
preset: "ts-jest",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
"^@components/(.*)$": "<rootDir>/src/components/$1",
},
};moduleNameMapper maps alias patterns to real paths. The line "^@/(.*)$": "<rootDir>/src/$1" translates @/utils into src/utils. Make sure this pattern is consistent with the paths configuration in tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
}
}Keeping aliases in sync between tsconfig.json and moduleNameMapper avoids confusing "module not found" errors.
With ts-jest, you get type safety inside the test itself:
interface Pengguna {
id: number;
nama: string;
}
function sapa(pengguna: Pengguna): string {
return `Halo, ${pengguna.nama}`;
}
test("menyapa pengguna bertipe", () => {
const pengguna: Pengguna = { id: 1, nama: "arif" };
expect(sapa(pengguna)).toBe("Halo, arif");
});const pengguna: Pengguna = ... ensures the test only accepts objects that match the type. If sapa changes its contract, the type checker rejects it before runtime — precisely the compile-time behavior we want.
When ts-jest encounters a type error, the test fails with a compilation message. There are times when you want to bypass the type on a single line — for instance when testing boundaries — but use as unknown and similar sparingly. A type error thrown in a test is a signal that the code contract changed and the test must be updated, not avoided.
Episode 9 closed the gap between TypeScript and Jest: choosing between ts-jest, which checks types, and the fast Babel, configuring the transform, mapping module aliases consistently with tsconfig, and writing safe typed tests.
Key takeaways:
@types/jest provides types for the entire testing API.preset: "ts-jest" sets up automatic TypeScript transformation.moduleNameMapper maps aliases so Jest recognizes paths like TypeScript.moduleNameMapper in sync with paths in tsconfig.In the next episode, episode 10, we'll cover test coverage — enabling coverage reports in Jest, understanding line, branch, function, and statement coverage, setting thresholds as a quality gate, and using coverage to maintain quality in CI.