Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Typescript

BSecurity

Sets up and repairs TypeScript projects: picks tsconfig.json settings for a Node.js service, an npm library or a bundled web app, runs type-checking in CI, and replaces `any` and unsafe casts with types the compiler can verify. Use when someone asks to "set up TypeScript", "fix this tsconfig", "fix a TypeScript error", "upgrade to TypeScript 6 or 7", "migrate JavaScript to TypeScript", "publish types for a package", "run .ts files in Node" or "make this type-safe". Covers the changed defaults...

155 stars
0 votes
0 copies
0 views
Added 10/4/2026
developmentjavascripttypescriptgojavabashreactvuenodegitapi

Works with

terminalcliapi

Security Analysis

B88/100
mediumInstalls packages at runtime which could introduce malicious dependencies
mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 2 files and shows the line behind each finding

Scanned 10/4/2026

$npx -y skills add TerminalSkills/skills --skill typescript --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Typescript?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Typescript
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-typescript/badge)](https://www.skillsdirectory.com/skills/terminalskills-typescript)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: typescript
description: >-
  Sets up and repairs TypeScript projects: picks tsconfig.json settings for a
  Node.js service, an npm library or a bundled web app, runs type-checking in
  CI, and replaces `any` and unsafe casts with types the compiler can verify.
  Use when someone asks to "set up TypeScript", "fix this tsconfig", "fix a
  TypeScript error", "upgrade to TypeScript 6 or 7", "migrate JavaScript to
  TypeScript", "publish types for a package", "run .ts files in Node" or "make
  this type-safe". Covers the changed defaults in TypeScript 6.0 and 7.0,
  module and moduleResolution, strict mode, project references, declaration
  output, narrowing, satisfies and common compiler errors.
license: Apache-2.0
compatibility: "TypeScript 5.9, 6.0 or 7.0; Node.js 20+ (22.18+ to run .ts files without a build step)"
metadata:
  author: terminal-skills
  version: "1.0.0"
  category: development
  tags: ["typescript", "tsconfig", "type-checking", "type-safety", "javascript-migration"]
  repository: https://github.com/microsoft/TypeScript
---

# TypeScript — Configure, Type-Check and Migrate

## Overview

TypeScript 7.0 (July 2026) is the native port of the compiler: the same `tsc` command, usually 8–12x faster on a full build, with no programmatic API yet. It keeps the defaults introduced in 6.0, which differ from 5.x, so a `tsconfig.json` copied from an older project often fails. This skill covers settings per target, type-checking in CI, running `.ts` files directly, patterns that keep types truthful, and migrating JavaScript.

## Instructions

### Check the compiler version first

Run `npx tsc --version`; the defaults depend on it.

| Option | Default in 5.9 and earlier | Default in 6.0 and 7.0 |
|---|---|---|
| `strict` | `false` | `true` |
| `types` | every package in `node_modules/@types` | `[]` |
| `rootDir` | inferred from the input files | the directory of `tsconfig.json` |
| `module` | `commonjs` | `esnext` |
| `target` | `es5` | `es2025` (latest stable ES version) |
| `noUncheckedSideEffectImports` | `false` | `true` |

Deprecated in 6.0 (error TS5101/TS5107, silenced by `"ignoreDeprecations": "6.0"`) and removed in 7.0 (TS5102/TS5108, cannot be silenced): `target: es5`, `downlevelIteration`, `moduleResolution: node`/`node10`/`classic`, `module: amd`/`umd`/`systemjs`/`none`, `baseUrl`, `outFile`, `esModuleInterop: false`, `alwaysStrict: false`.

### Choose settings by what runs the code

Node.js service, compiled by `tsc` and run from `dist/`:

```json
{
  "compilerOptions": {
    "module": "nodenext",
    "target": "es2023",
    "lib": ["es2023"],
    "types": ["node"],
    "rootDir": "./src",
    "outDir": "./dist",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "skipLibCheck": true,
    "sourceMap": true
  },
  "include": ["src"]
}
```

- `module: nodenext` implies `moduleResolution: nodenext`. A file is ESM or CommonJS according to `"type"` in `package.json` or a `.mts`/`.cts` extension.
- In ESM files a relative import names the output file: `import { parseInvoice } from "./invoice.js"`.
- An explicit `lib` without `dom` keeps browser globals such as `window` out of server code.
- `node20` (5.9+) is a fixed alternative to the moving `nodenext` and implies `target: es2023`.

Web app built by a bundler (Vite, esbuild, webpack). The bundler emits and `tsc` only checks. `module: preserve` implies `moduleResolution: bundler`, and from 6.0 `dom` includes `dom.iterable`:

```json
{
  "compilerOptions": {
    "module": "preserve",
    "target": "es2023",
    "lib": ["es2023", "dom"],
    "types": ["vite/client"],
    "jsx": "react-jsx",
    "noEmit": true,
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "strict": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}
```

Library published to npm — `tsc` emits JavaScript and declarations:

```json
{
  "compilerOptions": {
    "module": "node18",
    "target": "es2022",
    "types": [],
    "rootDir": "./src",
    "outDir": "./dist",
    "declaration": true,
    "declarationMap": true,
    "strict": true,
    "verbatimModuleSyntax": true,
    "isolatedDeclarations": true,
    "skipLibCheck": true
  },
  "include": ["src"]
}
```

The matching `package.json`; `"types"` must be the first condition in each `exports` entry:

```json
{
  "name": "@northwind/booking-rules",
  "version": "1.0.0",
  "type": "module",
  "exports": { ".": { "types": "./dist/index.d.ts", "default": "./dist/index.js" } },
  "files": ["dist"]
}
```

`moduleResolution: bundler` in a library accepts extensionless imports that fail in Node.js, so use a `node*` mode. `isolatedDeclarations` (5.5+) requires explicit types on exports (TS9013 otherwise). Check the package before publishing with `npx @arethetypeswrong/cli --pack . --profile esm-only`.

### Know what `strict` covers

`strict` turns on `noImplicitAny`, `strictNullChecks`, `strictFunctionTypes`, `strictBindCallApply`, `strictPropertyInitialization`, `strictBuiltinIteratorReturn`, `noImplicitThis`, `useUnknownInCatchVariables` and `alwaysStrict`. It does not turn on `noUncheckedIndexedAccess`, `exactOptionalPropertyTypes`, `noImplicitOverride` or `noFallthroughCasesInSwitch`; add those by name.

### Type-check in CI

```bash
npx tsc --noEmit                # one project
npx tsc -b                      # project references, in dependency order
npx tsc --noEmit --checkers 2   # 7.0 only: fewer checker threads on a small runner (default 4)
```

- Vite, esbuild, swc, tsx and Node.js remove types without checking them. Only `tsc` reports type errors.
- `tsc` writes output even when it reports errors unless `noEmitOnError` is set; `tsc -b` never does.
- From 6.0, `tsc src/invoice.ts` next to a `tsconfig.json` is error TS5112. Pre-commit hooks that pass file names must check the whole project; `--ignoreConfig` drops every project setting.

### Split a monorepo with project references

The root `tsconfig.json` only lists the projects: `{ "files": [], "references": [{ "path": "./packages/pricing" }, { "path": "./packages/api" }] }`. Each package extends a shared `tsconfig.base.json`:

```json
{
  "compilerOptions": {
    "composite": true,
    "declarationMap": true,
    "module": "nodenext",
    "rootDir": "${configDir}/src",
    "outDir": "${configDir}/dist"
  }
}
```

`composite` turns on `declaration` and `incremental`. Each package lists the packages it imports in its own `references`. `${configDir}` (5.5+) resolves against the config that extends the base. `tsc -b --verbose` explains why a project was rebuilt and `tsc -b --clean` deletes outputs.

### Run TypeScript without a build step

```bash
npx tsx src/server.ts         # esbuild-based: enums and tsconfig paths work
npx tsx watch src/server.ts
node src/report.ts            # built-in type stripping
```

Node.js type stripping is on by default from 22.18 and 23.6, and stable from 24.12 and 25.2. Its limits:

- It ignores `tsconfig.json`, so `paths` aliases fail. Use `"imports": { "#lib/*": "./src/lib/*" }` in `package.json`.
- Syntax that needs code generation throws `ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`: `enum`, parameter properties, namespaces with runtime code, `import x = require()`. Node.js 26 removed `--experimental-transform-types`.
- Imports need the real extension (`./booking.ts`) and type imports need the `type` keyword.
- `.tsx` files and files under `node_modules` are refused.
- To have `tsc` report the same limits, set `erasableSyntaxOnly`, `verbatimModuleSyntax`, and `allowImportingTsExtensions` (with `noEmit`) or `rewriteRelativeImportExtensions` (when emitting).

### Keep types truthful

```ts
import { z } from "zod";
// One variant per state: a field of one state cannot be read in another.
type Payment =
  | { status: "pending" }
  | { status: "captured"; capturedAt: Date; receiptUrl: string }
  | { status: "failed"; declineCode: string };

export function summary(p: Payment): string {
  switch (p.status) {
    case "pending": return "Awaiting capture";
    case "captured": return `Receipt: ${p.receiptUrl}`;
    case "failed": return `Declined (${p.declineCode})`;
    default: {
      const unhandled: never = p; // a new variant makes this line fail to compile
      throw new Error(`Unhandled payment: ${JSON.stringify(unhandled)}`);
    }
  }
}

// satisfies checks the shape and keeps the literal keys; an annotation would widen them to string.
export const retryDelaysMs = { card_declined: 0, network_error: 2_000, rate_limited: 30_000 } satisfies Record<string, number>;
export type RetryReason = keyof typeof retryDelaysMs;

// unknown at the boundary, validated once, typed afterwards.
const WebhookEvent = z.object({ id: z.string(), type: z.enum(["payment.captured", "payment.failed"]), amountCents: z.number().int() });
export function parseWebhook(body: unknown) {
  return WebhookEvent.parse(body); // not: body as WebhookEvent
}
```

### Fix common compiler errors

| Error | Cause | Fix |
|---|---|---|
| TS2591 `Cannot find name 'process'` | `types` is `[]` from 6.0 | `npm i -D @types/node`, then `"types": ["node"]` |
| TS5011, or output in `dist/src/` | `rootDir` is no longer inferred | `"rootDir": "./src"` |
| TS2835 `Relative import paths need explicit file extensions` | ESM under `nodenext` | import `./invoice.js`, the output name |
| TS1484 `is a type and must be imported using a type-only import` | `verbatimModuleSyntax` | `import { type Invoice }` |
| TS7016 `Could not find a declaration file for module` | package ships no types | install its `@types/` package, or add `declare module "legacy-pricing";` to a `.d.ts` file |
| TS18048 `is possibly 'undefined'` | null checks, indexed access | narrow with `if`; avoid the `!` assertion |
| TS2375 `... with 'exactOptionalPropertyTypes: true'` | `undefined` passed to an optional property | omit the key, or declare `label?: string \| undefined` |
| TS18046 `'e' is of type 'unknown'` | catch variable | `e instanceof Error ? e.message : String(e)` |
| TS1294 `not allowed when 'erasableSyntaxOnly' is enabled` | `enum`, parameter property | `as const` object plus a union type; assign fields in the constructor |

### Migrate a JavaScript codebase

1. Add a `tsconfig.json` with `"allowJs": true`, `"checkJs": false`, `"noEmit": true` and an explicit `"strict": false` (6.0+ defaults to `true`). Run `npx tsc --noEmit` in CI from the first commit.
2. Rename files that import no other local file first: `.js` to `.ts`, `.jsx` to `.tsx`. Add `// @ts-check` to files that stay JavaScript.
3. Type the boundaries before the internals: API responses, database rows, environment variables.
4. Turn on one flag per pull request: `noImplicitAny`, then `strictNullChecks`, then `strict`, then `noUncheckedIndexedAccess`.
5. Suppress what cannot be fixed yet with `// @ts-expect-error BOOK-412 untyped discount()`, not `@ts-ignore`: it becomes error TS2578 once the cause is gone.
6. Remove `allowJs` when no `.js` file is left.

## Examples

### Example 1: Set up a Node.js service with a CI type-check

**User request:** "Set up TypeScript for our invoice API on Node 24 and make CI fail on type errors."

```bash
npm install -D typescript @types/node tsx
npm pkg set type=module scripts.typecheck="tsc --noEmit" scripts.build="tsc" scripts.dev="tsx watch src/server.ts"
```

Write the Node.js service `tsconfig.json` from above, then add `npm run typecheck` as a CI step before the build.

**Result:** `npm run typecheck` exits 0 on clean code. After `{ status: "refunded"; refundRef: string }` is added to the `InvoiceState` union, it exits 1 and names the `switch` that does not handle it:

```text
src/invoice.ts(30,13): error TS2322: Type '{ status: "refunded"; refundRef: string; }' is not assignable to type 'never'.
```

### Example 2: Repair a project after upgrading from 5.9 to 7.0

**User request:** "We moved ledger-service from TypeScript 5.9 to 7 and tsc fails before it checks any code."

```text
tsconfig.json(5,25): error TS5108: Option 'moduleResolution=node10' has been removed. Please remove it from your configuration.
tsconfig.json(6,5): error TS5102: Option 'baseUrl' has been removed. Please remove it from your configuration.
tsconfig.json(7,27): error TS5090: Non-relative paths are not allowed. Did you forget a leading './'?
tsconfig.json(9,5): error TS5011: The common source directory of 'tsconfig.json' is './src'. The 'rootDir' setting must be explicitly set to this or another path to adjust your output's file layout.
```

Change only the affected options in `tsconfig.json`:

```diff
-    "moduleResolution": "node",
-    "baseUrl": "./src",
-    "paths": { "@lib/*": ["lib/*"] },
+    "moduleResolution": "bundler",
+    "paths": { "@lib/*": ["./src/lib/*"] },
+    "types": ["node"],
+    "rootDir": "./src",
```

**Result:** the configuration errors are gone and `tsc` reports the code that 5.9 accepted because `strict` was off, here `src/billing/invoice-total.ts(10,34): error TS7006: Parameter 'items' implicitly has an 'any' type.` Fix each one, or set `"strict": false` and raise strictness later as in the migration steps.

## Guidelines

- TypeScript 7.0 has no programmatic API (7.1 is expected to add a new one). typescript-eslint, and the Vue, Svelte, Astro and MDX toolchains need 6.0. Install both: `npm i -D typescript@npm:@typescript/typescript6 @typescript/native@npm:typescript@^7.0.2` gives `tsc` (7.0), `tsc6` (6.0) and the 6.0 API under `import "typescript"`.
- `tsc` never rewrites `paths` aliases in emitted JavaScript. With plain `tsc` output, `@lib/money` fails at runtime in Node.js; use `package.json` `"imports"` or a bundler.
- Replace `as` casts on external data with validation. Keep `as const`, and `as` after a runtime check the compiler cannot follow.
- Prefer a union of string literals to `enum`: it needs no emitted code and works with type stripping.
- JSDoc checking is stricter in 7.0: `@enum`, Closure-style `function(string): void` and postfix `!` are no longer recognised.
- Use the `zod` skill for schema design, `tsup` for bundling a library, `vite` for the app build, `eslint` or `biome` for lint rules, `vitest` for tests, and `react` for component typing.

Attribution

TerminalSkillsTerminalSkills
View sourceSee grades on GitHubMore from TerminalSkills →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

286712 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Writing Plans

Use when you have a spec or requirements for a multi-step task, before touching code

2927051 votes
View all in development →