Skip to main content

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.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.