What it isAlways-on coding rules. GitHub Copilot applies them to files matching **/*.ts,**/*.tsx,**/*.mts,**/*.cts; the Claude Code version is a path-scoped rule generated from the same file. Why use instructions →
Install
This repository (recommended)
Adds .github/instructions/typescript.instructions.md — commit it so everyone's Copilot follows the same rules.
Nothing to invoke — edit a matching file and Copilot picks the rules up. Adjust applyTo if your repository layout differs.
This repository (recommended)
Adds .claude/rules/typescript.md — commit it. Claude loads it when it reads a matching file.
npx -y github:AGCO-Global/org-skills add instructions typescript --tool claude
Just for me, every repository
Save it in your user profile instead.
npx -y github:AGCO-Global/org-skills add instructions typescript --tool claude --user
Use it
Nothing to invoke. Adjust the paths globs if your repository layout differs.
Commands run in your repository folder and need Node.js 20+. They use your normal git sign-in to GitHub, so they work while the repository is private. Run npx -y github:AGCO-Global/org-skills list to see everything available.
These apply to TypeScript anywhere — browser, server, mobile, scripts. Framework files
(react, angular, react-native, nodejs) add their own rules and do not repeat these.
Security rules live in secure-coding.instructions.md and frontend-security.instructions.md.
Compiler settings
Keep strict: true. Each flag it enables catches a class of runtime bug; turning one off to
clear errors moves the failure to production.
Turn on noUncheckedIndexedAccess for new projects: arr[0] and map[key] can be undefined,
and pretending otherwise is a common source of crashes.
Use isolatedModules and verbatimModuleSyntax, with import type for type-only imports, so
bundlers and transpilers cannot disagree about what is erased.
Types
No any. Use unknown and narrow — any disables checking for everything it touches, silently
and transitively.
Do not use as to silence an error. A type assertion is a claim the compiler cannot verify; if
you are right, narrow instead, and if you are wrong it fails at runtime. as const and
satisfies are fine — they add information rather than override it.
No non-null ! to clear a warning. Handle the null case, or narrow with a check that also
documents the invariant.
Let inference do local variables; write explicit types on exported functions, public APIs and
module boundaries, where the type is documentation and a change to it is a breaking change.
Prefer a discriminated union over an object with many optional fields. "Loading or loaded or
failed" as one type with a status field makes impossible states unrepresentable; four optional
fields makes them inevitable.
Prefer a union of literals or a const object over enum; enums have runtime semantics and
declaration-merging behaviour that surprise people.
Mark shared and returned data readonly where callers should not mutate it.
Untrusted input
Anything crossing a boundary — HTTP response, request body, query string, environment variable,
JSON.parse, message payload, file contents — is unknown until validated. An interface
describes what you hope arrived; it checks nothing at runtime.
Parse it with a schema validator and derive the static type from the schema, so the type and the
runtime check can never drift apart.
Validate environment variables once at startup and export the typed result. A config value that
is undefined should stop the process immediately, not surface as a confusing failure later.
Async
Never leave a promise floating. An unawaited promise loses its error and its ordering; await
it, return it, or attach explicit handling. Enable no-floating-promises in the linter.
catch binds unknown. Narrow before use — instanceof Error — because anything can be thrown.
Do not mix await in a loop with work that could run concurrently; use Promise.all when the
operations are independent, and keep the loop when they are not.
Errors and nullability
Distinguish "absent" from "empty" deliberately, and pick one of null or undefined per
codebase rather than both.
Throw Error (or a subclass), never a string, so there is a stack trace.
Preserve the original error when re-throwing — use cause rather than discarding it.
Modules
No default exports for anything with a name worth keeping; named exports survive renames, refactors
and find-all-references.
Keep index barrel files thin, or skip them. Deep barrels create import cycles that appear as
undefined at runtime long after the change that caused them.
---
name: "TypeScript"
description: "Always-on, stack-neutral TypeScript rules — strictness, typing untrusted input, async correctness and safe narrowing."
applyTo: "**/*.ts,**/*.tsx,**/*.mts,**/*.cts"
---
# TypeScript rules
These apply to TypeScript anywhere — browser, server, mobile, scripts. Framework files
(`react`, `angular`, `react-native`, `nodejs`) add their own rules and do not repeat these.
Security rules live in `secure-coding.instructions.md` and `frontend-security.instructions.md`.
## Compiler settings
- Keep `strict: true`. Each flag it enables catches a class of runtime bug; turning one off to
clear errors moves the failure to production.
- Turn on `noUncheckedIndexedAccess` for new projects: `arr[0]` and `map[key]` can be `undefined`,
and pretending otherwise is a common source of crashes.
- Use `isolatedModules` and `verbatimModuleSyntax`, with `import type` for type-only imports, so
bundlers and transpilers cannot disagree about what is erased.
## Types
- No `any`. Use `unknown` and narrow — `any` disables checking for everything it touches, silently
and transitively.
- Do not use `as` to silence an error. A type assertion is a claim the compiler cannot verify; if
you are right, narrow instead, and if you are wrong it fails at runtime. `as const` and
`satisfies` are fine — they add information rather than override it.
- No non-null `!` to clear a warning. Handle the null case, or narrow with a check that also
documents the invariant.
- Let inference do local variables; write explicit types on exported functions, public APIs and
module boundaries, where the type is documentation and a change to it is a breaking change.
- Prefer a discriminated union over an object with many optional fields. "Loading or loaded or
failed" as one type with a `status` field makes impossible states unrepresentable; four optional
fields makes them inevitable.
- Prefer a union of literals or a `const` object over `enum`; enums have runtime semantics and
declaration-merging behaviour that surprise people.
- Mark shared and returned data `readonly` where callers should not mutate it.
## Untrusted input
- Anything crossing a boundary — HTTP response, request body, query string, environment variable,
`JSON.parse`, message payload, file contents — is `unknown` until validated. An interface
describes what you *hope* arrived; it checks nothing at runtime.
- Parse it with a schema validator and derive the static type from the schema, so the type and the
runtime check can never drift apart.
- Validate environment variables once at startup and export the typed result. A config value that
is `undefined` should stop the process immediately, not surface as a confusing failure later.
## Async
- Never leave a promise floating. An unawaited promise loses its error and its ordering; `await`
it, return it, or attach explicit handling. Enable `no-floating-promises` in the linter.
- `catch` binds `unknown`. Narrow before use — `instanceof Error` — because anything can be thrown.
- Do not mix `await` in a loop with work that could run concurrently; use `Promise.all` when the
operations are independent, and keep the loop when they are not.
## Errors and nullability
- Distinguish "absent" from "empty" deliberately, and pick one of `null` or `undefined` per
codebase rather than both.
- Throw `Error` (or a subclass), never a string, so there is a stack trace.
- Preserve the original error when re-throwing — use `cause` rather than discarding it.
## Modules
- No default exports for anything with a name worth keeping; named exports survive renames, refactors
and find-all-references.
- Keep `index` barrel files thin, or skip them. Deep barrels create import cycles that appear as
`undefined` at runtime long after the change that caused them.
---
paths:
- "**/*.ts"
- "**/*.tsx"
- "**/*.mts"
- "**/*.cts"
---
<!-- TypeScript — generated from instructions/general/typescript.instructions.md for Claude Code. Edit that file, not this one. -->
# TypeScript rules
These apply to TypeScript anywhere — browser, server, mobile, scripts. Framework files
(`react`, `angular`, `react-native`, `nodejs`) add their own rules and do not repeat these.
Security rules live in `secure-coding.instructions.md` and `frontend-security.instructions.md`.
## Compiler settings
- Keep `strict: true`. Each flag it enables catches a class of runtime bug; turning one off to
clear errors moves the failure to production.
- Turn on `noUncheckedIndexedAccess` for new projects: `arr[0]` and `map[key]` can be `undefined`,
and pretending otherwise is a common source of crashes.
- Use `isolatedModules` and `verbatimModuleSyntax`, with `import type` for type-only imports, so
bundlers and transpilers cannot disagree about what is erased.
## Types
- No `any`. Use `unknown` and narrow — `any` disables checking for everything it touches, silently
and transitively.
- Do not use `as` to silence an error. A type assertion is a claim the compiler cannot verify; if
you are right, narrow instead, and if you are wrong it fails at runtime. `as const` and
`satisfies` are fine — they add information rather than override it.
- No non-null `!` to clear a warning. Handle the null case, or narrow with a check that also
documents the invariant.
- Let inference do local variables; write explicit types on exported functions, public APIs and
module boundaries, where the type is documentation and a change to it is a breaking change.
- Prefer a discriminated union over an object with many optional fields. "Loading or loaded or
failed" as one type with a `status` field makes impossible states unrepresentable; four optional
fields makes them inevitable.
- Prefer a union of literals or a `const` object over `enum`; enums have runtime semantics and
declaration-merging behaviour that surprise people.
- Mark shared and returned data `readonly` where callers should not mutate it.
## Untrusted input
- Anything crossing a boundary — HTTP response, request body, query string, environment variable,
`JSON.parse`, message payload, file contents — is `unknown` until validated. An interface
describes what you *hope* arrived; it checks nothing at runtime.
- Parse it with a schema validator and derive the static type from the schema, so the type and the
runtime check can never drift apart.
- Validate environment variables once at startup and export the typed result. A config value that
is `undefined` should stop the process immediately, not surface as a confusing failure later.
## Async
- Never leave a promise floating. An unawaited promise loses its error and its ordering; `await`
it, return it, or attach explicit handling. Enable `no-floating-promises` in the linter.
- `catch` binds `unknown`. Narrow before use — `instanceof Error` — because anything can be thrown.
- Do not mix `await` in a loop with work that could run concurrently; use `Promise.all` when the
operations are independent, and keep the loop when they are not.
## Errors and nullability
- Distinguish "absent" from "empty" deliberately, and pick one of `null` or `undefined` per
codebase rather than both.
- Throw `Error` (or a subclass), never a string, so there is a stack trace.
- Preserve the original error when re-throwing — use `cause` rather than discarding it.
## Modules
- No default exports for anything with a name worth keeping; named exports survive renames, refactors
and find-all-references.
- Keep `index` barrel files thin, or skip them. Deep barrels create import cycles that appear as
`undefined` at runtime long after the change that caused them.