How to Set Up TypeScript with Every Major Framework
·PkgPulse Team
TL;DR
Every major framework ships with TypeScript support out of the box in 2026. The setup is increasingly trivial — npm create vite@latest or npx create-next-app generates a working tsconfig. The important customization is in strict settings and module resolution. This guide covers the right tsconfig for each framework and the gotchas that cost hours.
Key Takeaways
"strict": true— always enable; catches 80% of runtime bugs at compile time"moduleResolution": "bundler"— the correct setting for Vite-based projects"noEmit": true— when the bundler handles transpilation (not tsc)@tsconfig/bases— community-maintained base configs for every runtime- TypeScript 5.x — required for most 2026 frameworks (Angular, NestJS support both)
Base tsconfig Recommendations
# @tsconfig/bases — community-maintained tsconfig presets
npm install -D @tsconfig/strictest # Most strict (recommended)
npm install -D @tsconfig/node20 # For Node.js 20 projects
npm install -D @tsconfig/next # For Next.js
Next.js
// tsconfig.json (Next.js generates this automatically)
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true, // Next.js handles transpilation
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler", // Next.js 14+
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve", // Next.js transforms JSX
"incremental": true,
"plugins": [{ "name": "next" }], // Next.js TypeScript plugin
"paths": {
"@/*": ["./src/*"] // Path alias
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
// Next.js TypeScript gotchas:
// 1. Page props typing
interface Props {
params: { id: string };
searchParams: { [key: string]: string | string[] | undefined };
}
export default function Page({ params, searchParams }: Props) { ... }
// 2. Server component return type
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'My App',
};
// 3. API route typing (App Router)
import type { NextRequest } from 'next/server';
export async function GET(request: NextRequest) {
return Response.json({ data: 'ok' });
}
Vite + React
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler", // Vite-specific
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true, // Vite handles emit
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"types": ["vite/client"] // import.meta.env types
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
// tsconfig.node.json (for vite.config.ts)
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts"]
}
SvelteKit
// tsconfig.json (SvelteKit generates this)
{
"extends": "./.svelte-kit/tsconfig.json", // SvelteKit-managed base
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true
}
}
// .svelte-kit/tsconfig.json is auto-generated — don't edit it
// Customize only the parts in your tsconfig.json
Hono (Edge/Node.js)
// tsconfig.json for Hono on Cloudflare Workers
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "bundler",
"strict": true,
"lib": ["ES2020"], // No DOM — edge runtime
"types": ["@cloudflare/workers-types"], // Cloudflare types
"isolatedModules": true,
"resolveJsonModule": true,
"noEmit": true // Wrangler handles transpilation
},
"include": ["src", "worker-configuration.d.ts"]
}
// tsconfig.json for Hono on Node.js
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext", // Node.js resolution
"strict": true,
"lib": ["ES2022"],
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"sourceMap": true
},
"include": ["src"]
}
Fastify (Node.js API)
// tsconfig.json for Fastify
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
// package.json for Fastify TypeScript
{
"scripts": {
"dev": "tsx watch src/server.ts", // tsx: run TypeScript directly
"build": "tsc",
"start": "node dist/server.js"
}
}
Plain Node.js (scripts, CLIs)
// tsconfig.json for Node.js scripts
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext", // For .mts / .cts support
"moduleResolution": "NodeNext",
"strict": true,
"noUncheckedIndexedAccess": true, // Array/Object access can be undefined
"lib": ["ES2022"],
"outDir": "dist",
"declaration": true,
"sourceMap": true
},
"include": ["src"]
}
Common tsconfig Mistakes
// ❌ Mistake 1: Wrong moduleResolution for bundled projects
"moduleResolution": "node" // Outdated — use "bundler" for Vite/Next.js
// ❌ Mistake 2: Not enabling strict
"strict": false // Allows implicit any, null checks skipped — bugs guaranteed
// ❌ Mistake 3: Missing noUncheckedIndexedAccess
// users[0].name // Can crash if users is empty — not caught without this flag
"noUncheckedIndexedAccess": true // Add this
// ❌ Mistake 4: skipLibCheck: false (slow)
"skipLibCheck": false // Type-checks all node_modules — very slow, little benefit
// ❌ Mistake 5: target too old
"target": "ES5" // Produces verbose output for modern runtimes; use ES2020+
Compare framework package health on PkgPulse.
See the live comparison
View nextjs vs. remix on PkgPulse →