TypeScript with Vite and Frontend Apps

Introduction

Modern frontends use Vite (or similar tools) for fast dev servers and production bundles. TypeScript type-checks your code—often via tsc while Vite transpiles. This chapter walks through a React + TypeScript Vite app and explains how responsibilities split between tools.

Prerequisites

Scaffold a Project

bash
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install

Typical layout:

text
my-app/
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── vite.config.ts
└── src/
    ├── main.tsx
    ├── App.tsx
    └── vite-env.d.ts

npm run dev starts Vite. npm run build usually runs tsc -b then vite build.

Who Does What?

TaskTool
Dev server, HMRVite
TS → JS in devesbuild (via Vite)
Production bundleRollup (via Vite)
Full type-checktsc (noEmit: true)

Vite transpiles quickly; run tsc in CI to catch type errors Vite might skip.

tsconfig.app.json (Typical)

Path Aliases

vite.config.ts:

typescript
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "node:path";
 
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "src"),
    },
  },
});

tsconfig.app.json:

json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

Vite and TypeScript aliases must match.

Typed Component Example

src/components/Button.tsx:

typescript
type ButtonProps = {
  label: string;
  onClick: () => void;
};
 
export function Button({ label, onClick }: ButtonProps) {
  return (
    <button type="button" onClick={onClick}>
      {label}
    </button>
  );
}

Environment Variables

src/vite-env.d.ts:

typescript
/// <reference types="vite/client" />
 
interface ImportMetaEnv {
  readonly VITE_API_URL: string;
}
 
interface ImportMeta {
  readonly env: ImportMetaEnv;
}

Only variables prefixed with VITE_ are exposed to client code.

Scripts

json
{
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "preview": "vite preview",
    "typecheck": "tsc -b --noEmit"
  }
}

Vanilla TypeScript Template

bash
npm create vite@latest my-vanilla-app -- --template vanilla-ts

Same pattern: Vite bundles; tsc checks types.

FAQ

Why is dev so fast?

esbuild strips types without full program analysis. tsc runs separately.

Use tsc to build the SPA?

Use vite build for JS; tsc for type-checking (and .d.ts only for libraries).

Vue or Svelte?

Use vue-ts or svelte-ts templates—same noEmit + bundler split. For Vue 3 + defineProps + vue-tsc, see the Vue track chapter 18 and chapter 02.

ESLint?

Add @typescript-eslint and run alongside tsc in CI.