| name | typescript-coder |
| description | Expert 10x engineer with extensive knowledge of TypeScript fundamentals, migration strategies, and best practices. Use when asked to "add TypeScript", "migrate to TypeScript", "add type checking", "create TypeScript config", "fix TypeScript errors", or work with .ts/.tsx files. Supports JavaScript to TypeScript migration, JSDoc type annotations, tsconfig.json configuration, and type-safe code patterns. |
TypeScript Coder Skill
Master TypeScript development with expert-level knowledge of type systems, migration strategies, and modern JavaScript/TypeScript patterns. This skill transforms you into a 10x engineer capable of writing type-safe, maintainable code and migrating existing JavaScript projects to TypeScript with confidence.
When to Use This Skill
- User asks to "add TypeScript", "migrate to TypeScript", or "convert to TypeScript"
- Need to "add type checking" or "fix TypeScript errors" in a project
- Creating or configuring
tsconfig.json for a project
- Working with
.ts, .tsx, .mts, or .d.ts files
- Adding JSDoc type annotations to JavaScript files
- Debugging type errors or improving type safety
- Setting up TypeScript in a Node.js or JavaScript project
- Creating type definitions or ambient declarations
- Implementing advanced TypeScript patterns (generics, conditional types, mapped types)
Prerequisites
- Basic understanding of JavaScript (ES6+)
- Node.js and npm/yarn installed (for TypeScript compilation)
- Familiarity with the project structure and build tools
- Access to the
typescript package (can be installed if needed)
Shorthand Keywords
Keywords to trigger this skill as if using a command-line tool:
openPrompt = ["typescript-coder", "ts-coder"]
Use these shorthand commands to quickly invoke TypeScript expertise without lengthy explanations. For example:
typescript-coder --check "this code"
typescript-coder check this type guard
ts-coder migrate this file
ts-coder --migrate project-to-typescript
Role and Expertise
As a TypeScript expert, you operate with:
- Deep Type System Knowledge: Understanding of TypeScript's structural type system, generics, and advanced types
- Migration Expertise: Proven strategies for incremental JavaScript to TypeScript migration
- Best Practices: Knowledge of TypeScript patterns, conventions, and anti-patterns
- Tooling Mastery: Configuration of TypeScript compiler, build tools, and IDE integration
- Problem Solving: Ability to resolve complex type errors and design type-safe architectures
Core TypeScript Concepts
The TypeScript Type System
TypeScript uses structural typing (duck typing) rather than nominal typing:
interface Point {
x: number;
y: number;
}
const point: Point = { x: 10, y: 20 };
const point3D = { x: 1, y: 2, z: 3 };
const point2D: Point = point3D;
Type Inference
TypeScript infers types when possible, reducing boilerplate:
const message = "Hello, TypeScript!";
const count = 42;
const names = ["Alice", "Bob", "Charlie"];
function add(a: number, b: number) {
return a + b;
}
Key TypeScript Features
| Feature | Purpose | When to Use |
|---|
| Interfaces | Define object shapes | Defining data structures, API contracts |
| Type Aliases | Create custom types | Union types, complex types, type utilities |
| Generics | Type-safe reusable components | Functions/classes that work with multiple types |
| Enums | Named constants | Fixed set of related values |
| Type Guards | Runtime type checking | Narrowing union types safely |
| Utility Types | Transform types | Partial<T>, Pick<T, K>, Omit<T, K>, etc. |
Step-by-Step Workflows
Task 1: Install and Configure TypeScript
For a new or existing JavaScript project:
-
Install TypeScript as a dev dependency:
npm install --save-dev typescript
-
Install type definitions for Node.js (if using Node.js):
npm install --save-dev @types/node
-
Initialize TypeScript configuration:
npx tsc --init
-
Configure tsconfig.json for your project:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
-
Add build script to package.json:
{
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"check": "tsc --noEmit"
}
}
Task 2: Migrate JavaScript to TypeScript (Incremental Approach)
Safe, incremental migration strategy:
-
Enable TypeScript to process JavaScript files:
{
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"noEmit": true
}
}
-
Add JSDoc type annotations to JavaScript files (optional intermediate step):
function add(a, b) {
return a + b;
}
const names = ["Alice", "Bob"];
const user = {
id: 1,
name: "Alice"
};
-
Rename files incrementally from .js to .ts:
mv src/utils/helpers.js src/utils/helpers.ts
-
Fix TypeScript errors in converted files:
- Add explicit type annotations where inference fails
- Define interfaces for complex objects
- Handle
any types appropriately
- Add type guards for runtime checks
-
Gradually convert remaining files:
- Start with utilities and shared modules
- Move to leaf components (no dependencies)
- Finally convert orchestration/entry files
-
Enable strict mode progressively:
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true,
"strictNullChecks": true
}
}
Task 3: Define Types and Interfaces
Creating robust type definitions:
-
Define interfaces for data structures:
interface User {
id: number;
name: string;
email: string;
age?: number;
readonly createdAt: Date;
}
interface ApiResponse<T> {
success: boolean;
data?: T;
error?: {
code: string;
message: string;
};
}
-
Use type aliases for complex types:
type Status = 'pending' | 'active' | 'completed' | 'failed';
type Employee = User & {
employeeId: string;
department: string;
salary: number;
};
type TransformFn<T, U> = (input: T) => U;
type NonNullable<T> = T extends null | undefined ? never : T;
-
Create type definitions in .d.ts files for external modules:
declare module 'custom-module' {
export interface Config {
apiKey: string;
timeout?: number;
}
export function initialize(config: Config): Promise<void>;
export function fetchData<T>(endpoint: string): Promise<T>;
}
Task 4: Work with Generics
Type-safe reusable components:
-
Generic functions:
function identity<T>(value: T): T {
return value;
}
const num = identity(42);
const str = identity("hello");
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: "Alice", age: 30 };
const name = getProperty(user, "name");
const age = getProperty(user, "age");
-
Generic classes:
class DataStore<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
get(index: number): T | undefined {
return this.items[index];
}
filter(predicate: (item: T) => boolean): T[] {
return this.items.filter(predicate);
}
}
const numberStore = new DataStore<number>();
numberStore.add(42);
const userStore = new DataStore<User>();
userStore.add({ id: 1, name: "Alice", email: "alice@example.com" });
-
Generic interfaces:
interface Repository<T> {
findById(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
create(item: Omit<T, 'id'>): Promise<T>;
update(id: string, item: Partial<T>): Promise<T>;
delete(id: string): Promise<boolean>;
}
class UserRepository implements Repository<User> {
async findById(id: string): Promise<User | null> {
return null;
}
}
Task 5: Handle Type Errors
Common type errors and solutions:
-
"Property does not exist" errors:
const user = {};
user.name = "Alice";
interface User {
name: string;
}
const user: User = { name: "Alice" };
const user = {} as User;
user.name = "Alice";
interface DynamicObject {
[key: string]: any;
}
const user: DynamicObject = {};
user.name = "Alice";
-
"Cannot find name" errors:
const env = process.env.NODE_ENV;
const env = process.env.NODE_ENV;
-
any type issues:
function process(data) {
return data.value;
}
function process(data: { value: number }): number {
return data.value;
}
function process<T>(data: T): T {
return data;
}
-
Union type narrowing:
function processValue(value: string | number) {
return value.toUpperCase();
if (typeof value === "string") {
return value.toUpperCase();
}
return value.toString();
}
Task 6: Configure for Specific Environments
Environment-specific configurations:
Node.js Project
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"types": ["node"],
"moduleResolution": "node",
"esModuleInterop": true
}
}
Browser/DOM Project
{
"compilerOptions": {
"target": "ES2020",
"module": "esnext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"moduleResolution": "bundler",
"resolveJsonModule": true,
"noEmit": true
}
}
Library/Package
{
"compilerOptions": {
"target": "ES2020",
"module": "esnext",
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src"
}
}
TypeScript Best Practices
Do's
- ✅ Enable strict mode (
"strict": true) for maximum type safety
- ✅ Use type inference - let TypeScript infer types when it's obvious
- ✅ Prefer interfaces over type aliases for object shapes (better error messages)
- ✅ Use
unknown instead of any - forces type checking before use
- ✅ Create utility types for common transformations
- ✅ Use const assertions (
as const) for literal types
- ✅ Leverage type guards for runtime type checking
- ✅ Document complex types with JSDoc comments
- ✅ Use discriminated unions for type-safe state management
- ✅ Keep types DRY - extract and reuse type definitions
Don'ts
- ❌ Don't use
any everywhere - defeats the purpose of TypeScript
- ❌ Don't ignore TypeScript errors with
@ts-ignore without good reason
- ❌ Don't over-complicate types - balance safety with readability
- ❌ Don't use type assertions excessively - indicates design issues
- ❌ Don't duplicate type definitions - use shared types
- ❌ Don't forget null/undefined checks - enable
strictNullChecks
- ❌ Don't use enums for everything - consider union types instead
- ❌ Don't skip type definitions for external libraries - install
@types/*
- ❌ Don't disable strict flags without justification
- ❌ Don't mix JavaScript and TypeScript in production - complete the migration
Common Patterns
Pattern 1: Discriminated Unions
Type-safe state management:
type LoadingState = { status: 'loading' };
type SuccessState<T> = { status: 'success'; data: T };
type ErrorState = { status: 'error'; error: Error };
type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState;
function handleState<T>(state: AsyncState<T>) {
switch (state.status) {
case 'loading':
console.log('Loading...');
break;
case 'success':
console.log('Data:', state.data);
break;
case 'error':
console.log('Error:', state.error.message);
break;
}
}
Pattern 2: Builder Pattern
Type-safe fluent API:
class QueryBuilder<T> {
private filters: Array<(item: T) => boolean> = [];
private sortFn?: (a: T, b: T) => number;
private limitCount?: number;
where(predicate: (item: T) => boolean): this {
this.filters.push(predicate);
return this;
}
sortBy(compareFn: (a: T, b: T) => number): this {
this.sortFn = compareFn;
return this;
}
limit(count: number): this {
this.limitCount = count;
return this;
}
execute(data: T[]): T[] {
let result = data.filter(item =>
this.filters.every(filter => filter(item))
);
if (this.sortFn) {
result = result.sort(this.sortFn);
}
if (this.limitCount) {
result = result.slice(0, this.limitCount);
}
return result;
}
}
const users = [];
const result = new QueryBuilder<User>()
.where(u => u.age > 18)
.where(u => u.email.includes('@example.com'))
.sortBy((a, b) => a.name.localeCompare(b.name))
.limit(10)
.execute(users);
Pattern 3: Type-Safe Event Emitter
type EventMap = {
'user:created': { id: string; name: string };
'user:updated': { id: string; changes: Partial<User> };
'user:deleted': { id: string };
};
class TypedEventEmitter<T extends Record<string, any>> {
private listeners: { [K in keyof T]?: Array<(data: T[K]) => void> } = {};
on<K extends keyof T>(event: K, listener: (data: T[K]) => void): void {
if (!this.listeners[event]) {
this.listeners[event] = [];
}
this.listeners[event]!.push(listener);
}
emit<K extends keyof T>(event: K, data: T[K]): void {
const eventListeners = this.listeners[event];
if (eventListeners) {
eventListeners.forEach(listener => listener(data));
}
}
}
const emitter = new TypedEventEmitter<EventMap>();
emitter.on('user:created', (data) => {
console.log(data.id, data.name);
});
emitter.emit('user:created', { id: '123', name: 'Alice' });
Troubleshooting
| Issue | Cause | Solution |
|---|
| Module not found | Missing type definitions | Install @types/[package-name] or add declare module |
| Implicit any errors | noImplicitAny enabled | Add explicit type annotations |
| Cannot find global types | Missing lib in compilerOptions | Add to lib: ["ES2020", "DOM"] |
| Type errors in node_modules | Third-party library types | Add skipLibCheck: true to tsconfig.json |
| Import errors with .ts extension | Import resolving issues | Use imports without extensions |
| Build takes too long | Compiling too many files | Use incremental: true and tsBuildInfoFile |
| Type inference not working | Complex inferred types | Add explicit type annotations |
| Circular dependency errors | Import cycles | Refactor to break cycles, use interfaces |
Advanced TypeScript Features
Mapped Types
Transform existing types:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface User {
id: number;
name: string;
email: string;
}
type ReadonlyUser = Readonly<User>;
type PartialUser = Partial<User>;
type UserNameEmail = Pick<User, 'name' | 'email'>;
Conditional Types
Types that depend on conditions:
type IsString<T> = T extends string ? true : false;
type A = IsString<string>;
type B = IsString<number>;
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
function getUser() {
return { id: 1, name: "Alice" };
}
type User = ReturnType<typeof getUser>;
Template Literal Types
String manipulation at type level:
type Greeting<T extends string> = `Hello, ${T}!`;
type WelcomeMessage = Greeting<"World">;
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">;
type HoverEvent = EventName<"hover">;
TypeScript Configuration Reference
Key tsconfig.json Options
| Option | Purpose | Recommended |
|---|
strict | Enable all strict type checking | true |
target | ECMAScript target version | ES2020 or higher |
module | Module system | commonjs (Node) or esnext (bundlers) |
lib | Include type definitions | ["ES2020"] + DOM if browser |
outDir | Output directory | ./dist |
rootDir | Root source directory | ./src |
sourceMap | Generate source maps | true for debugging |
declaration | Generate .d.ts files | true for libraries |
esModuleInterop | Enable interop between CommonJS and ES modules | true |
skipLibCheck | Skip type checking of .d.ts files | true for performance |
forceConsistentCasingInFileNames | Enforce consistent file casing | true |
resolveJsonModule | Allow importing JSON files | true if needed |
allowJs | Allow JavaScript files | true during migration |
checkJs | Type check JavaScript files | false during migration |
noEmit | Don't emit files (use external bundler) | true with bundlers |
incremental | Enable incremental compilation | true for faster builds |
Migration Checklist
When migrating a JavaScript project to TypeScript:
Phase 1: Setup
Phase 2: Incremental Migration
Phase 3: Strengthen Types
Phase 4: Full Strict Mode
Phase 5: Maintenance
References
This skill includes bundled reference documentation for TypeScript essentials.
Reference Documentation (references/)
Core Concepts & Fundamentals
- basics.md - TypeScript fundamentals, simple types, type inference, and special types
- essentials.md - Core TypeScript concepts every developer should know
- cheatsheet.md - Quick reference for control flow, classes, interfaces, types, and common patterns
Type System & Language Features
- types.md - Advanced types, conditional types, mapped types, type guards, and recursive types
- classes.md - Class syntax, inheritance, generics, and utility types
- elements.md - Arrays, tuples, objects, enums, functions, and casting
- keywords.md - keyof, null handling, optional chaining, and template literal types
- miscellaneous.md - Async programming, promises, decorators, and JSDoc integration
External Resources
Summary
The TypeScript Coder skill empowers you to write type-safe, maintainable code with expert-level TypeScript knowledge. Whether migrating existing JavaScript projects or starting new TypeScript projects, apply these proven patterns, workflows, and best practices to deliver production-quality code with confidence.
Remember: TypeScript is a tool for developer productivity and code quality. Use it to catch errors early, improve code documentation, and enable better tooling—but don't let perfect types prevent shipping working code.