| name | TypeScript Ecosystem |
| description | This skill should be used when the user asks to "write typescript", "typescript config", "tsconfig", "type definition", "generics", "utility types", or works with TypeScript language patterns and configuration. Provides comprehensive TypeScript ecosystem patterns and best practices. |
Provide comprehensive patterns for TypeScript language, configuration, type system, and tooling integration.
Read - Analyze tsconfig.json and TypeScript source files
Edit - Modify TypeScript configurations and source code
Bash - Run tsc, tsx, eslint, and build commands
mcp__context7__get-library-docs - Fetch latest TypeScript documentation
Enable all strict checking options (strict: true) for maximum type safety
nodenext for ESM Node.js, bundler for Vite/esbuild/webpack projects
Built-in generic types: Partial, Required, Pick, Omit, Record, Extract, Exclude, ReturnType
Use type guards (typeof, instanceof, in, custom predicates) to safely narrow union types
Node.js version-specific recommended configurations
Current LTS - use ES2023 for stable features
Upcoming - use ES2024 for latest features
{
"compilerOptions": {
"target": "ES2023",
"lib": ["ES2023"],
"module": "nodenext",
"moduleResolution": "nodenext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Node.js 22 LTS - use ES2023 target/lib for stable features
{
"compilerOptions": {
"target": "ES2024",
"lib": ["ES2024"],
"module": "nodenext",
"moduleResolution": "nodenext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
Node.js 24 (upcoming) - use ES2024 target/lib for latest features
<strict_options>
Enables all strict type-checking options
null and undefined handled explicitly
Stricter function type checking
Check bind, call, apply methods
Class properties must be initialized
Error on implicit any types
Error on missing return statements
Error on implicit this
Add undefined to index signatures
Error on unused local variables
Error on unused parameters
</strict_options>
<module_resolution>
Modern Node.js ESM resolution (recommended)
{
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext"
}
}
Requires "type": "module" in package.json
<pattern name="bundler">
<description>For projects using bundlers (Vite, esbuild, webpack)</description>
<example>
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler"
}
}
</example>
</pattern>
<pattern name="path_aliases">
<description>Import path aliases</description>
<example>
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"]
}
}
}
</example>
<warning>baseUrl: deprecated in TS 6.0, removed in TS 7.0; prefer paths without baseUrl</warning>
<warning>moduleResolution: "node" (alias "node10"): deprecated in TS 5.x; use "nodenext" or "bundler"</warning>
<decision_tree name="when_to_use">
<question>Are you using a bundler or working with Node.js modules?</question>
<if_yes>Configure appropriate moduleResolution: bundler for bundlers, nodenext for Node.js</if_yes>
<if_no>Stick with default module resolution for simple projects</if_no>
</decision_tree>
</pattern>
</module_resolution>
<project_references>
Monorepo and incremental builds
{
"compilerOptions": {
"composite": true,
"incremental": true,
"tsBuildInfoFile": ".tsbuildinfo"
},
"references": [
{ "path": "../shared" },
{ "path": "../core" }
]
}
Use tsc --build for incremental compilation
</project_references>
<type_patterns>
<utility_types>
Make all properties optional
Make all properties required
Make all properties readonly
Object type with key K and value V
Select specific properties from T
Exclude specific properties from T
Exclude types from union
Extract types from union
Remove null and undefined
Get function return type
Get function parameter types as tuple
Unwrap Promise type
</utility_types>
Basic generic function
function identity<T>(arg: T): T {
return arg;
}
<pattern name="constraints">
<description>Generic with type constraints</description>
<example>
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
</example>
</pattern>
<pattern name="default_type">
<description>Generic with default type parameter</description>
<example>
interface Container<T = string> {
value: T;
}
</example>
</pattern>
<pattern name="multiple_constraints">
<description>Multiple generic parameters with constraints</description>
<example>
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
</example>
</pattern>
<conditional_types>
Basic conditional type
type IsString<T> = T extends string ? true : false;
<pattern name="infer">
<description>Extract types within conditional</description>
<example>
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;
type ArrayElement<T> = T extends (infer E)[] ? E : never;
</example>
</pattern>
<pattern name="distributive">
<description>Distributes over union types</description>
<example>
type ToArray<T> = T extends any ? T[] : never;
// ToArray<string | number> = string[] | number[]
</example>
</pattern>
</conditional_types>
<mapped_types>
Basic mapped type
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
<pattern name="key_remapping">
<description>Map keys with renaming</description>
<example>
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
</example>
</pattern>
<pattern name="filtering">
<description>Filter properties by type</description>
<example>
type OnlyStrings<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
</example>
</pattern>
</mapped_types>
<template_literal_types>
Template literal type construction
type EventName = on${Capitalize<string>};
type Locale = ${Language}-${Country};
<pattern name="inference">
<description>Extract parameters from template literals</description>
<example>
type ExtractRouteParams<T> = T extends `${string}:${infer Param}/${infer Rest}`
? Param | ExtractRouteParams<Rest>
: T extends `${string}:${infer Param}`
? Param
: never;
</example>
</pattern>
</template_literal_types>
<type_guards>
Built-in typeof type guard
function process(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toFixed(2);
}
<pattern name="instanceof">
<description>Built-in instanceof type guard</description>
<example>
function handle(error: Error | string) {
if (error instanceof Error) {
return error.message;
}
return error;
}
</example>
</pattern>
<pattern name="custom">
<description>Custom type guard function</description>
<example>
interface Cat { meow(): void; }
interface Dog { bark(): void; }
function isCat(pet: Cat | Dog): pet is Cat {
return (pet as Cat).meow !== undefined;
}
</example>
<decision_tree name="when_to_use">
<question>Does TypeScript need help narrowing union types?</question>
<if_yes>Implement custom type guard with is predicate</if_yes>
<if_no>Use built-in typeof or instanceof guards</if_no>
</decision_tree>
</pattern>
<pattern name="in_operator">
<description>Property existence type guard</description>
<example>
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim();
} else {
animal.fly();
}
}
</example>
</pattern>
</type_guards>
<branded_types>
Nominal typing via branding
type UserId = string & { readonly **brand: unique symbol };
type OrderId = string & { readonly **brand: unique symbol };
function createUserId(id: string): UserId {
return id as UserId;
}
</example>
<note>Prevent mixing similar primitive types</note>
</pattern>
</branded_types>
<satisfies_operator>
Type checking without widening
const config = {
endpoint: "/api",
timeout: 3000,
} satisfies Record<string, string | number>;
// config.endpoint is inferred as "/api" (literal), not string
</satisfies_operator>
</type_patterns>
<runtime_patterns>
<error_handling>
Rust-inspired Result type for error handling
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
function parseJson<T>(json: string): Result<T> {
try {
return { success: true, data: JSON.parse(json) };
} catch (e) {
return { success: false, error: e as Error };
}
}
</example>
<decision_tree name="when_to_use">
<question>Do you need explicit error handling without exceptions?</question>
<if_yes>Use Result type for functional error handling</if_yes>
<if_no>Use try-catch for traditional exception handling</if_no>
</decision_tree>
</pattern>
<pattern name="custom_errors">
<description>Custom error classes with additional context</description>
<example>
class ValidationError extends Error {
constructor(
message: string,
public readonly field: string,
public readonly code: string
) {
super(message);
this.name = "ValidationError";
}
}
</example>
</pattern>
<pattern name="error_cause">
<description>Error chaining with cause (ES2022+)</description>
<example>
try {
await fetchData();
} catch (e) {
throw new Error("Failed to fetch data", { cause: e });
}
</example>
</pattern>
</error_handling>
<async_patterns>
Parallel promise execution
const [users, posts] = await Promise.all([
fetchUsers(),
fetchPosts(),
]);
<pattern name="promise_allSettled">
<description>Handle mixed success/failure</description>
<example>
const results = await Promise.allSettled([
fetchUser(1),
fetchUser(2),
fetchUser(3),
]);
const successful = results
.filter((r): r is PromiseFulfilledResult<User> => r.status === "fulfilled")
.map((r) => r.value);
</example>
</pattern>
<pattern name="async_iterator">
<description>Async generator for pagination</description>
<example>
async function* paginate<T>(fetchPage: (page: number) => Promise<T[]>) {
let page = 0;
while (true) {
const items = await fetchPage(page++);
if (items.length === 0) break;
yield* items;
}
}
for await (const item of paginate(fetchUsers)) {
console.log(item);
}
</example>
</pattern>
</async_patterns>
<module_patterns>
ES module export patterns
// Named exports
export const helper = () => {};
export type Config = { /* ... _/ };
// Default export
export default class Service {}
// Re-exports
export { util } from "./util.js";
export type { UtilOptions } from "./util.js";
</example>
</pattern>
<pattern name="barrel_exports">
<description>index.ts for clean imports</description>
<example>
// src/components/index.ts
export { Button } from "./Button.js";
export { Input } from "./Input.js";
export type { ButtonProps, InputProps } from "./types.js";
</example>
<warning>Can impact tree-shaking; use sparingly</warning>
</pattern>
<pattern name="dynamic_import">
<description>Code splitting with dynamic imports</description>
<example>
const module = await import("./heavy-module.js");
module.doSomething();
</example>
</pattern>
</module_patterns>
</runtime_patterns>
ESLint with TypeScript (flat config)
// eslint.config.js
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.strictTypeChecked,
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
}
);
</example>
<note>import.meta.dirname requires Node.js 20.11+ or 21.2+ (not available in Node.js 18 LTS)</note>
</pattern>
<key_rules>
<rule name="@typescript-eslint/no-explicit-any">Prefer unknown over any</rule>
<rule name="@typescript-eslint/no-unused-vars">Detect unused variables</rule>
<rule name="@typescript-eslint/strict-boolean-expressions">Require explicit boolean conditions</rule>
<rule name="@typescript-eslint/no-floating-promises">Require awaiting promises</rule>
<rule name="@typescript-eslint/prefer-nullish-coalescing">Use ?? over ||</rule>
</key_rules>
Prettier configuration for TypeScript
{
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5",
"printWidth": 100
}
Modern, fast test runner
// vitest.config.ts
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
globals: true,
environment: "node",
coverage: {
provider: "v8",
reporter: ["text", "json", "html"],
},
},
});
</example>
</pattern>
</vitest>
<jest>
<pattern name="config">
<description>Jest configuration for TypeScript</description>
<example>
// jest.config.ts
import type { Config } from "jest";
const config: Config = {
preset: "ts-jest",
testEnvironment: "node",
roots: ["<rootDir>/src"],
moduleNameMapper: {
"^@/(.\*)$": "<rootDir>/src/$1",
},
};
export default config;
</example>
</pattern>
</jest>
<build_tools>
TypeScript compiler commands
<use_case name="compile">tsc - Compile TypeScript</use_case>
<use_case name="build">tsc --build - Incremental build (monorepo)</use_case>
<use_case name="check">tsc --noEmit - Type check only</use_case>
<use_case name="watch">tsc --watch - Watch mode</use_case>
<tsx>
<tool name="tsx">
<description>TypeScript execution with esbuild</description>
<use_case name="run">tsx src/index.ts - Run TypeScript directly</use_case>
<use_case name="watch">tsx watch src/index.ts - Watch mode</use_case>
</tool>
</tsx>
<tsup>
<pattern name="config">
<description>Bundle TypeScript libraries</description>
<example>
// tsup.config.ts
import { defineConfig } from "tsup";
export default defineConfig({
entry: ["src/index.ts"],
format: ["cjs", "esm"],
dts: true,
clean: true,
sourcemap: true,
});
</example>
</pattern>
</tsup>
</build_tools>
<context7_integration>
<library_id>/microsoft/typescript</library_id>
<trust_score>9.9</trust_score>
16397
<usage_pattern>
Resolve library ID if needed (already known: /microsoft/typescript)
Fetch documentation with specific topic
Configuration options and patterns
Generic type patterns
Built-in utility types
Module resolution strategies
</usage_pattern>
<common_queries>
Strict compiler options
Path aliases configuration
Type declaration generation
ESM support in Node.js
</common_queries>
</context7_integration>
<anti_patterns>
Overusing 'any' defeats type safety
Use 'unknown' and narrow with type guards
Excessive 'as' casts bypass type checking
Use type guards or proper typing
Missing type annotations with noImplicitAny disabled
Enable strict mode, add explicit types
Barrel files can hurt tree-shaking
Use direct imports for large modules
Enums have runtime overhead and quirks
Use const objects with 'as const'
const Status = {
Active: "active",
Inactive: "inactive",
} as const;
type Status = (typeof Status)[keyof typeof Status];
</example>
Namespaces are legacy, use ES modules
Use regular imports/exports
Decorators add complexity and are still experimental
Prefer composition and higher-order functions
<best_practices>
Enable strict mode in all projects
Use noUncheckedIndexedAccess for safer array/object access
Prefer 'unknown' over 'any' for unknown types
Use 'satisfies' to check types without widening
Create branded types for domain primitives
Use Result types for error handling over exceptions
Keep type definitions close to usage
Export types separately with 'export type'
Use 'const' assertions for literal types
Prefer interfaces for public APIs, types for unions/utilities
</best_practices>
Enable strict mode in all TypeScript projects
Never use any without documented justification; prefer unknown
Run tsc --noEmit before committing to catch type errors
Use noUncheckedIndexedAccess for safer array/object access
Export types separately with 'export type' for clarity
Define types before implementation for better design
Use satisfies operator to check types without widening
Understand TypeScript code requirements
1. Check tsconfig.json for project settings
2. Review existing type patterns in project
3. Identify type dependencies and imports
Write type-safe TypeScript code
1. Define types before implementation
2. Use strict type checking features
3. Follow project naming conventions
Verify TypeScript correctness
1. Run tsc --noEmit for type checking
2. Check with ESLint for style issues
3. Verify tests pass
<error_escalation>
Minor type inference issue
Add explicit type annotation
Type error in implementation
Fix type, verify with tsc
Breaking type change in public API
Stop, present migration options to user
Type safety bypass with any or type assertion
Block operation, require proper typing
</error_escalation>
Enable strict mode in tsconfig.json
Define explicit types for public APIs
Use type guards for runtime type checking
Using any type without justification
Type assertions without validation
Ignoring TypeScript errors with ts-ignore
<related_skills>
Symbol-level navigation for type definitions and interfaces
Fetch latest TypeScript compiler and tooling documentation
Debug type errors and investigate compilation issues
</related_skills>