Configuration questions sound dull and reveal a lot: whether you know why moduleResolution: 'bundler' exists, what verbatimModuleSyntax forces, how declaration files reach consumers, and what TypeScript 7 removed. In 2026 they also include "does your code run on Node without a build step".
strict (on), module: 'esnext' (or preserve), moduleResolution: 'bundler' (resolves like Vite: exports conditions, extensionless imports allowed), target current (es2024/esnext; the bundler downlevels), isolatedModules (each file transpilable alone, required by esbuild/Oxc), verbatimModuleSyntax (imports are emitted exactly as written; type-only imports must say import type, which also fixes side-effect and CJS interop ambiguities), skipLibCheck (do not type-check node_modules declarations), noUncheckedIndexedAccess, exactOptionalPropertyTypes, paths for aliases (Nuxt generates ~, @, #imports, #shared), types to whitelist ambient packages..ts files by stripping types (no type checking, no downlevelling), which requires erasable syntax only: no enum, namespace with values, parameter properties or import x = require. erasableSyntaxOnly (5.8) enforces that; rewriteRelativeImportExtensions (5.7) lets you write ./file.ts imports. Handy for scripts (this app's scripts/ uses jiti, an alternative).references: [{ path }], composite: true) split a repository into independently checked projects with tsc -b; Nuxt 4 uses them to give app, server, shared and node contexts different globals. TypeScript 7 builds referenced projects in parallel (--builders)..d.ts files describe shapes without emitting code. Ambient declarations (declare const __APP_VERSION__: string, declare module '*.svg' { const src: string; export default src }) for globals and asset imports; module augmentation (declare module 'vue' { interface ComponentCustomProperties {} }) merges into existing modules and requires the file to be a module (export {}); declare global adds to the global scope from within a module.declaration: true (or isolatedDeclarations (5.5) for parallel emit without type checking, requiring explicit return types on exports), the types condition in exports next to import/require, typesVersions for legacy resolution, and no reliance on @types the consumer does not have.node16/nodenext mirror Node's ESM/CJS rules (extensions required in ESM, exports honoured, .d.ts paired with .mts/.cts); bundler relaxes extensions for bundler-built code; node10 (classic Node) is removed in TypeScript 7.baseUrl, moduleResolution: node10/classic, target: es5, downlevelIteration, module: amd/umd/system, esModuleInterop: false, alwaysStrict: false), flipped some defaults, and added stableTypeOrdering so 6 and 7 output identical types. Use --ignoreDeprecations 6.0 only as a stopgap.tsc is now native; @typescript/typescript6 provides tsc6), 8–12× faster full builds, multithreaded checking (--checkers, --builders, --singleThreaded), new defaults (strict: true, module: esnext, target = current stable ES, noUncheckedSideEffectImports: true, rootDir: ./, types: []), the deprecated options become hard errors, template literal types are Unicode-code-point aware, and a new LSP server with far fewer crashes. Type-checking behaviour matches 6.0. Vue, Svelte, Astro and MDX template checking through the compiler API is planned for 7.1, so vue-tsc projects stay on 6 until then (verify).tsc --noEmit (or vue-tsc) in CI; --extendedDiagnostics and --generateTrace to find slow types; skipLibCheck keeps third-party declaration errors from blocking you.A tsconfig for an application repository (Nuxt generates its own; this is the shape to recognise):
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"module": "esnext",
"moduleResolution": "bundler",
"target": "es2024",
"lib": ["es2026", "dom", "dom.iterable"],
"isolatedModules": true,
"verbatimModuleSyntax": true,
"erasableSyntaxOnly": true,
"skipLibCheck": true,
"noEmit": true,
"types": ["node", "vite/client"]
},
"include": ["src", "scripts", "test"]
}
Nuxt's project-reference layout, which is why declarations must sit in the right tree:
{
"files": [],
"references": [
{ "path": "./.nuxt/tsconfig.app.json" },
{ "path": "./.nuxt/tsconfig.server.json" },
{ "path": "./.nuxt/tsconfig.shared.json" },
{ "path": "./.nuxt/tsconfig.node.json" }
]
}
Declarations you actually write in an app:
// Build-time constant injected through vite.define
declare const __APP_VERSION__: string
// Asset modules that Vite handles
declare module '*.svg?raw' {
const content: string
export default content
}
// Global augmentation from inside a module file
declare global {
interface Window { __analytics?: { track: (event: string) => void } }
}
export {}
Shipping a typed package with dual output and isolated declarations:
{
"type": "module",
"exports": {
".": { "types": "./dist/index.d.ts", "import": "./dist/index.mjs", "require": "./dist/index.cjs" }
}
}
{
"extends": "./tsconfig.json",
"compilerOptions": { "declaration": true, "isolatedDeclarations": true, "emitDeclarationOnly": true, "outDir": "dist", "noEmit": false }
}
With verbatimModuleSyntax, import { Product } from './types' where Product is only a type is an error: the import would survive to runtime and fail. Write import type { Product } or import { type Product, helper }. It looks pedantic and it removes a class of "module has no export" runtime errors after bundling.
baseUrl was the usual way to make paths work; TypeScript 7 removes it and paths are now relative to the config file. Nuxt-generated configs already do this, but hand-written monorepo configs from 2022 break on upgrade.
The exact list of removed options and new defaults in 7.0, the status of the 7.1 API that Vue tooling needs, and the current vue-tsc peer range.
verbatimModuleSyntax in a project and fix the errors; count how many imports were type-only.erasableSyntaxOnly and run a script with node script.ts on Node 24; replace the first enum it rejects with an as const object.tsc --noEmit with both; read the 6.0 deprecation warnings your config triggers."7.0, released in July 2026, is the Go-native port: same type-checking semantics as 6.0 but eight to twelve times faster, with multithreaded checking and a rewritten language server. It changed defaults, strict on, module: esnext, types empty by default, and turned the options 6.0 had deprecated into hard errors: baseUrl, moduleResolution: node10, target: es5, downlevelIteration. For a Nuxt project the practical effect is indirect for now: .vue template checking needs the programmatic API planned for 7.1, so vue-tsc still runs on TypeScript 6, while server-only or shared packages can move to 7 today. The 6.0 deprecation warnings are the migration checklist."
"strict, plus noUncheckedIndexedAccess because array and record access returning T | undefined catches the most common runtime crash. moduleResolution: 'bundler' and isolatedModules so the types match how Vite actually resolves and transpiles. verbatimModuleSyntax so type-only imports are explicit and cannot leak into the runtime bundle. skipLibCheck so third-party declaration quirks do not block CI. And increasingly erasableSyntaxOnly, so scripts run directly on Node with type stripping and nobody adds an enum that breaks it."
Nothing yet. Notes filed here show up on this page and the section overview.
TypeScript with Vue and Nuxt
Typing props, emits, slots and models through the compiler macros, generic components, typing refs and injection, Nuxt's generated types — auto-imports, components, typed routes, typed $fetch, runtimeConfig and app.config augmentation — and where declarations must live.
Runtime validation and type safety
Types are erased, so safety comes from validating at boundaries — schemas with zod, valibot and ArkType under Standard Schema, deriving types from schemas, sharing them between Nuxt server and client, branded types, exhaustive checks, typed errors and Result types.