agentsclimarketplace

Tsconfig modern strict

Skill kongyo2/tsconfig-modern-strict/tsconfig-modern-strict

Install
npx -y skills add kongyo2/tsconfig-modern-strict --skill tsconfig-modern-strict

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use whenever a tsconfig.json is being created, edited, reviewed, troubleshot, or even just discussed. Triggers on any mention of "tsconfig", "TypeScript config", strict mode flags, module resolution, target/module decisions, project references, monorepo TS setup, library publishing config, path aliases, or "なんでこの型エラーが出る/出ない" debates that turn out to be config-shaped. Apply this skill even when the user only asks about one option — it encodes a coherent ESNext + maximum-strict policy that should drive the rest of the config to stay consistent. Default to this skill instead of free-recall whenever the answer involves a tsconfig field.

SKILL.md

13.2 KB, ~3.4k tokens by cl100k_base, as published. Nobody here has run it

tsconfig-modern-strict

Opinionated runbook for producing TypeScript configs that target modern toolchains with the strictest practical type checking.

Standing policy (override only with an explicit, stated reason):

  • target: "esnext". Downleveling is the bundler/runtime's job, not tsc's.
  • strict: true plus every recommended add-on flag in §3.
  • moduleResolution: "bundler" for app code, "nodenext" for native Node.
  • skipLibCheck: true. Always.
  • isolatedModules: true and verbatimModuleSyntax: true for any code touched by esbuild/SWC/Babel/Vite.

When the user proposes loosening any of these, ask why before agreeing. Most of the time the request comes from copy-pasted legacy advice rather than a real constraint.


1. Pick the use case first (decision tree)

Is tsc emitting JS?
├── No, a bundler emits  ─────────────────► §4.1  Browser app + bundler
└── Yes, tsc emits
    ├── Running on Node directly
    │   ├── ESM ("type": "module")  ─────► §4.2  Node ESM app
    │   └── CommonJS (legacy only)  ─────► adapt §4.2 (see notes)
    └── Publishing to npm
        ├── Single package           ────► §4.3  Library
        └── Monorepo                 ────► §4.4  Project references

Resolve the use case before writing or modifying a tsconfig. The four templates in §4 differ in ways that don't compose cleanly — picking wrong forces a rewrite, not a patch.


2. The trio that must agree: target / module / moduleResolution

These three options are co-dependent. Use this table; do not improvise.

ScenariotargetmodulemoduleResolution
Browser app via bundleresnextesnextbundler
Node.js native ESMesnextnodenextnodenext
Node.js CommonJS (legacy)es2022commonjsnode
Publishable library (build via tsc)es2020+esnextbundler
Deno / Bun scriptesnextesnextbundler

Common mismatches that produce confusing errors:

  • module: "commonjs" + moduleResolution: "bundler" — invalid.
  • module: "esnext" + moduleResolution: "node" — legacy resolver, won't see exports in package.json.
  • nodenext + extensionless imports — Node ESM requires .js on relative imports even when the source is .ts.

3. Strict policy (apply to every template)

Always on (strict: true covers these eight)

noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables, alwaysStrict.

Always add on top

These are not part of strict but should be enabled by default. Document any omission in the config with a comment.

FlagWhat it catches
noUncheckedIndexedAccessarr[i] and obj[k] become T | undefined — kills a huge class of bugs.
exactOptionalPropertyTypes?: no longer accepts an explicit undefined.
noImplicitOverrideSubclass overrides must say override.
noImplicitReturnsAll branches return when any branch does.
noFallthroughCasesInSwitchNo silent case fallthrough.
noUnusedLocalsUnused locals are errors.
noUnusedParametersUnused parameters are errors. Prefix with _ to opt out per parameter — never disable globally.
allowUnreachableCode: falseUnreachable code is an error, not a warning.
allowUnusedLabels: falseSame for labels.

Add when the toolchain supports it

FlagAdd when
verbatimModuleSyntaxAny non-tsc transpiler in the pipeline (esbuild, SWC, Babel, Vite).
isolatedModulesSame as above.
noPropertyAccessFromIndexSignatureThe codebase uses index signatures and you want explicit bracket access.
isolatedDeclarations (5.5+)Publishing a library and using a non-tsc declaration emitter.
erasableSyntaxOnly (5.8+)Source must be runnable after pure type-stripping (Node --experimental-strip-types, Deno, Bun). Disallows enum, parameter properties, namespaces.

Refuse to disable

Pushback list — if the user wants any of these turned off, ask what concrete problem they are trying to solve before agreeing.

  • strict (or any of its eight sub-flags individually)
  • skipLibCheck (turning it off blocks builds on a single broken .d.ts in node_modules)
  • noUnusedParameters globally (the _param escape hatch is the right answer)

4. Templates

Copy the matching one as a starting point, then layer project-specific tweaks (paths, lib, jsx) on top. Do not delete strict flags to "simplify".

4.1 Browser app + bundler (Vite, Next.js app code, Rspack, etc.)

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "bundler",
    "lib": ["esnext", "dom", "dom.iterable"],
    "jsx": "react-jsx",

    "noEmit": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,
    "resolveJsonModule": true,
    "allowImportingTsExtensions": true,

    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,

    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "allowUnreachableCode": false,
    "allowUnusedLabels": false
  },
  "include": ["src"]
}

Tweaks:

  • Drop "dom" and "dom.iterable" from lib for non-browser code.
  • Change jsx to "preserve" + set jsxImportSource for Preact/Solid.
  • Remove allowImportingTsExtensions if the bundler can't handle it.

4.2 Node.js ESM application

package.json must have "type": "module". Relative imports must include .js even when the source is .ts.

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "lib": ["esnext"],

    "outDir": "./dist",
    "rootDir": "./src",
    "sourceMap": true,

    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,

    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  },
  "include": ["src/**/*"],
  "exclude": ["**/*.test.ts", "**/*.spec.ts", "dist"]
}

For legacy CommonJS Node: change to "module": "commonjs", "moduleResolution": "node", drop verbatimModuleSyntax, and remove "type": "module" from package.json.

4.3 Publishable library (separate JS and .d.ts output)

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "bundler",

    "rootDir": "./src",
    "outDir": "./dist",
    "declarationDir": "./dist-types",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "allowImportingTsExtensions": false,

    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "skipLibCheck": true,
    "isolatedModules": true,
    "verbatimModuleSyntax": true,

    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  },
  "include": ["src/**/*"],
  "exclude": ["**/*.test.ts", "**/*.spec.ts"]
}

When publishing, also configure package.json exportstypes field first in each conditional block, fallback main/types at top level for old tooling. See references/full-reference.md §6.

4.4 Monorepo with project references

Root tsconfig.json:

{
  "files": [],
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/utils" },
    { "path": "./packages/app" }
  ]
}

Each package extends the shared base and sets composite:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "composite": true,
    "rootDir": "./src",
    "outDir": "./dist",
    "declaration": true,
    "declarationMap": true
  },
  "include": ["src/**/*"],
  "references": [{ "path": "../core" }]
}

Build with tsc --build (or tsc -b). Don't use plain tsc against the root — references won't resolve.


5. Path aliases

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

Rules:

  • paths only affects type checking. The bundler/runtime needs the same alias configured separately (Vite resolve.alias, webpack resolve.alias, Node import maps, etc.).
  • With moduleResolution: "bundler", baseUrl is optional.
  • One alias style per project. Don't mix @/ and ~/.

6. Pitfalls — apply as rules, not theory

When any of these come up, recognize the symptom and fix the cause directly.

SymptomCauseFix
Cannot find module './foo' in Node ESMMissing .js in importAdd .js extension (yes, on .ts source).
paths works in tsc, fails at runtimetsc doesn't rewrite imports under noEmitConfigure the bundler's alias too.
const enum rejectedisolatedModules: trueReplace with as const object.
Spread breaks exactOptionalPropertyTypes{...x, y: maybeUndef} makes y present-with-undefinedConditionally include the key, or widen to y?: T | undefined.
Stale type errors after config change.tsbuildinfo cacheDelete .tsbuildinfo and rebuild.
import type enforcement breaks buildsverbatimModuleSyntax + value/type mixSplit into two imports, or use import { type X, y }.
Single broken .d.ts blocks buildskipLibCheck: falseRe-enable skipLibCheck.
exports resolves wrong file for typestypes not first in conditional objectMove types to the top of each conditional block.

7. Diagnostic commands

When debugging a config, run these instead of guessing:

tsc --showConfig            # final resolved config after all `extends`
tsc --traceResolution       # every module-resolution step (huge output, pipe to a file)
tsc --extendedDiagnostics   # phase timings for performance work
tsc --listFiles             # every file the program is compiling

tsc --showConfig is the single most valuable debugging tool and underused. Run it first whenever a setting "isn't working".


8. Migration order (loose → strict)

When tightening an existing project, enable flags in this order to minimize churn. Run tsc --noEmit after each step. Commit between steps.

  1. strict: true
  2. noUnusedLocals + noUnusedParameters
  3. noImplicitReturns + noFallthroughCasesInSwitch
  4. noUncheckedIndexedAccess
  5. exactOptionalPropertyTypes
  6. verbatimModuleSyntax

Do not enable everything at once on an existing codebase — the error volume becomes unreadable and bugfixes get mixed with churn.


9. Sharing config across packages

Place common settings in tsconfig.base.json at the repo root and have each package extends it:

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": { "outDir": "./dist", "rootDir": "./src" },
  "include": ["src"]
}

extends accepts an array (TS 5.0+) for layered presets:

{ "extends": ["@tsconfig/strictest/tsconfig", "./tsconfig.base.json"] }

Useful community presets: @tsconfig/strictest, @tsconfig/node20, @tsconfig/node22.


When to consult references/full-reference.md

The reference file expands on what's in this skill with prose explanations of each option, the full strict-flag breakdown, library package.json exports patterns including subpath wildcards, and a longer pitfalls section. Pull it in when:

  • The user asks why an option behaves a certain way (this skill says "do X"; the reference says "because Y").
  • A package.json exports field needs to be authored or audited beyond the one-liner in §4.3.
  • Performance tuning is the goal (incremental, composite, project-reference graph design).
  • The user is on TypeScript ≤ 4.x and modern flag names don't apply.

What ships with it: 1 file

18.0 KB alongside SKILL.md

references/

Gives 0 of the 12 instructions most project setup skills give in ~3.4k tokens

Counted across 999 of the 1,637 authors here whose files we hold, read 2026-08-07

  • Ask one question at a timein 29 of 999, across 28 files
  • Detect the package manager from lockfilesin 28 of 999, across 9 files
  • Present findings to the userin 26 of 999, across 5 files
  • Explore current repo statein 24 of 999, across 3 files
  • Update the agent skills block in place if it existsin 24 of 999, across 3 files
  • Install husky lint-staged and prettierin 23 of 999, across 4 files
  • Create the lintstagedrc filein 22 of 999, across 3 files
  • Commit all changed filesin 22 of 999, across 3 files
  • Run lint-staged to verify it worksin 22 of 999, across 3 files
  • Create the husky pre-commit filein 21 of 999, across 2 files
  • Create a prettierrc file if missingin 21 of 999, across 2 files
  • Initialize huskyin 21 of 999, across 2 files

Said here and by no other author read

  • resolve the use case before writing the config
  • keep target module and moduleResolution consistent
  • enable strict and recommended add-on flags
  • add isolatedModules and verbatimModuleSyntax for non-tsc transpilers
  • use skipLibCheck true
  • ask why before loosening any standing policy

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 327,069. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.