About core-typescript
A base engineering skill for TypeScript projects, covering code generation, diff review, and compiler and ESLint configuration. It provides an enforceable checklist built around strict mode and is designed to compose with framework and architecture skills.
Key features
- 01Strict-mode compiler baseline
- 02Type safety and narrowing rules
- 03Data modeling and generics conventions
- 04Async, error, and module rules
- 05Generate, review, and configure workflows
Use cases
- 01Write TypeScript code against shared rules
- 02Review diffs and report rule violations
- 03Configure or audit tsconfig.json and ESLint
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ danielteles/ awesome-agent-skills --skill core-typescriptAfter installing, type/core-typescriptin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
assets/eslint.config.jstsconfig.base.jsonreferences/async.mdcompiler-config.mddata-modeling.mderrors.mdfunctions.mdgenerics.mdinference.mdlanguage-hygiene.mdlint.mdmodules.mdnarrowing.mdnullability.mdunsafe-types.mdutility-types.mdworked-example.mdDetails
From the project READMECore TypeScript Conventions — Base Engineering Skill
The language-level TypeScript rules for every project, framework or not. react, angular, and vue
extend it; architecture-and-design composes with it. Every rule assumes the compiler runs in
strict mode (compiler-config). Examples are plain TypeScript, no framework.
Builds on. Nothing — this is a base skill.
This SKILL.md is self-sufficient: the Ruleset below is the complete, enforceable list. Each
references/<topic>.md holds that group's reasoning and ❌ / ✅ code, and
references/worked-example.md a full review pass; open them for depth when your runtime allows.
How to Use This Skill
Pick the mode that matches the task. Do the steps in order.
| Mode | Steps |
|---|---|
| Generate — write new TypeScript | 1. Assume strict is on (compiler-config). 2. Write the code, applying the Ruleset as you go. 3. Annotate the return type of every exported function (functions). 4. Run the Ruleset as a checklist. Fix each fail before you hand off. |
| Review — check a diff | 1. Run the Ruleset against the diff. 2. Write one finding per fail, in the Output Format below. 3. Order the findings: must-fix first, then consider. 4. If nothing fails, say so in one line. Do not invent findings. |
Configure — set up or audit tsconfig.json and ESLint | 1. Start from assets/tsconfig.base.json and assets/eslint.config.js. 2. Turn on every flag in compiler-config and every rule in lint. 3. For a flag you cannot turn on yet, add a // TODO with the reason. 4. Do not relax a flag or disable a rule to clear an error. Fix the code. |
Output Format
Write one finding per line:
<severity> · <topic> · <file>:<line> — <what is wrong>. <the fix as an action>.
<severity>ismust-fix(breaks a rule in this skill or the build) orconsider(safe, but a rule prefers another form).<topic>is a Ruleset topic slug (unsafe-types,narrowing,async, …).
Rules for Every Mode
- Name the Ruleset topic when you enforce a rule.
- Prefer the simplest type that stays precise. A wider type hides bugs; an over-clever type slows the next reader.
- A type that needs a comment to explain it is a smell. Give it a name, or make it simpler.
Ruleset
compiler-config → references/compiler-config.md
-
strictis on, plusnoUncheckedIndexedAccess,exactOptionalPropertyTypes,noImplicitOverride,noFallthroughCasesInSwitch,noImplicitReturns,noUnusedLocals,noUnusedParameters,verbatimModuleSyntax, anderasableSyntaxOnly. - A flag is never relaxed to clear an error — the code is fixed instead.
unsafe-types → references/unsafe-types.md
- No
any: an unknown input is typedunknownand narrowed. Noas any, noas unknown as T. - No
asto force a type, and no!, unless the value is proven present on the line above — each such use has a guard or a comment that proves it safe. - No
Function,Object, or{}as a type (objectfor a non-primitive is fine). - No
@ts-ignore—@ts-expect-errorwith a comment.
inference → references/inference.md
- No annotation that only repeats what the compiler already infers exactly (exception: an exported API boundary — see
functions). -
satisfieschecks a literal against a shape without widening the value's type.
data-modeling → references/data-modeling.md
- A string set is a union of string literals or a frozen
as constobject — never a TypeScriptenumorconst enum. - Unchanging data is
readonly(readonly T[]for a list). - Mutually exclusive states are a discriminated union with a shared discriminant field. Design rationale:
architecture-and-design, patterns. - A domain id has its own branded type, minted with one sanctioned cast at the boundary. Design rationale:
architecture-and-design, type-safety.
narrowing → references/narrowing.md
-
unknownand unions are narrowed with a type guard (v is T) or an assertion function (asserts v is T), not a cast. - Every
switchon a union ends with anassertNeverdefault.
generics → references/generics.md
- A type parameter is added only when two types move together (an input and a return type); no single-use type parameter.
- A type parameter is constrained with
extends; a common one has a default; aconsttype parameter where the caller passes a literal.
utility-types → references/utility-types.md
- A related type is derived with
Pick/Omit/Partial/Required/Record/ReturnType/Parameters/Awaited/NonNullable/keyof/typeof/ indexed access / a template literal type — not hand-copied.
nullability → references/nullability.md
-
undefinedis the one empty value;nullonly for an external contract that sends it. -
array[i]andrecord[key]are read as possiblyundefined(needsnoUncheckedIndexedAccess). -
?.and??for a default —||only where0,'', andfalseare not valid values.
functions → references/functions.md
- Every exported function annotates its return type; a local, non-exported function infers it.
- One options object past three parameters — no long list of order-dependent, especially boolean, arguments.
- A union parameter over an overload set when the bodies match.
async → references/async.md
- No floating promise — every promise is awaited or explicitly marked
void. - Independent async work runs with
Promise.all; serialawaitonly for a step that needs the previous result. - A disposable resource (a timer, subscription, lock, or handle) is released with
using/await usingwhere the target supports explicit resource management.
errors → references/errors.md
- A
catchbinding isunknown(fromuseUnknownInCatchVariables) and is narrowed before any field read. - A thrown value is always an
Error— a custom type extendsErrorand setsname; never a string or a plain object.
modules → references/modules.md
- A type reference uses
import type/export typeor an inlinetypeon the name. - Named exports over a default export; no circular import between two modules; no project-wide barrel (a feature
index.tsis fine).
language-hygiene → references/language-hygiene.md
-
===/!==only — the one exception isx == null, which testsnullandundefinedtogether. -
Number.isNaN/Number.isFinite, not the coercing globals. -
constby default,letonly when reassigned, nevervar; a function parameter is not reassigned. - Real bit flags are a
constobject of powers of two plus a derived type, not a string-literal union.
lint → references/lint.md
-
typescript-eslintruns withstrict-type-checked(or at leastrecommended-type-checked), withno-floating-promises,no-explicit-any,consistent-type-imports, andswitch-exhaustiveness-checkon. - Prettier formats, so style is not a review topic.
Limits
This skill is language-level TypeScript. It does not cover:
- Architecture, layering, state management, and component design — see
architecture-and-design. - Framework APIs and patterns — see
react,angular, andvue. - Build tooling, bundlers, and monorepo setup beyond the
tsconfigbaseline incompiler-config. - Runtime schema libraries (Zod, Valibot) — named where relevant, not taught here.
This skill decides the syntax. It does not replace reading the code and understanding the domain.
References
This skill composes with:
architecture-and-design— the design layer. On a shared topic (discriminated unions, branded ids) it decides the design and this skill decides the syntax.react/angular/vue— extend this skill with their framework's specifics. On a language-point conflict, this skill wins.