| name | ms-lang-typescript |
| description | TypeScript 5.7+ development expertise with modern toolchain - Vitest 2.1 for 10x faster testing with native ESM support, Biome 1.9 for unified linting and formatting (75x faster than ESLint), strict type checking with advanced patterns (const type parameters, satisfies operator), React 19 and Next.js 15 integration with Error Boundaries and Suspense patterns, Zod runtime validation, type-safe environment variables, Constitution compliance (≤500 SLOC, ≤10 complexity), and comprehensive TDD workflow with TAG block integration |
Language: TypeScript 5.7+ Expert
Skill Metadata
| Field | Value |
|---|---|
| Version | 1.0.0 |
| Created | 2025-10-26 |
| TypeScript Support | 5.7+ (latest) |
| Allowed tools | Read, Bash, Grep |
| Auto-load | On demand when .ts, .tsx files detected |
| Trigger cues | TypeScript files, type safety, React/Next.js development |
What it does
Provides TypeScript 5.7+ expertise for My-Spec TDD development, including:
- ✅ Testing Framework: Vitest 2.1+ (fast, modern alternative to Jest)
- ✅ Code Quality: Biome 1.9+ (unified linter + formatter, replaces ESLint + Prettier)
- ✅ Type Safety: TypeScript 5.7+ strict mode with advanced patterns
- ✅ Package Management: npm/pnpm/bun (project preference)
- ✅ TypeScript 5.7 Features: Decorators, const type parameters, satisfies operator
- ✅ React/Next.js: Modern patterns with TypeScript integration
- ✅ Constitution Compliance: TRUST 5 principles, ≤500 SLOC files, ≤10 complexity
When to use
Automatic triggers:
- TypeScript code discussions,
.ts/.tsxfiles - "Writing TypeScript tests", "How to use Vitest", "TypeScript type hints"
- TypeScript SPEC implementation (
/ms.implement) - React/Next.js component development
Manual invocation:
- Review TypeScript code for TRUST 5 compliance
- Design TypeScript APIs or React components
- Troubleshoot type errors or build issues
- Migrate JavaScript to TypeScript
How it works (Best Practices)
1. Testing Framework (Vitest 2.1+)
Why Vitest over Jest?
- ⚡ 10x faster than Jest (native ESM support)
- 🔧 Zero config for TypeScript
- ✅ Jest-compatible API (easy migration)
- 🎯 Built-in coverage with c8/v8
Test Structure:
// tests/unit/calculator.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { Calculator } from '@/services/calculator';
describe('Calculator', () => {
let calculator: Calculator;
beforeEach(() => {
calculator = new Calculator();
});
it('should add two positive numbers', () => {
const result = calculator.add(2, 3);
expect(result).toBe(5);
});
it('should handle negative numbers', () => {
const result = calculator.add(-2, 3);
expect(result).toBe(1);
});
});
Key Points:
- ✅ Use Vitest (not Jest) for TypeScript projects
- ✅ One assertion per test (clarity)
- ✅ Descriptive test names ("should" convention)
- ✅
beforeEachfor setup/teardown - ✅ Coverage ≥85% enforced by quality gate
CLI Commands:
vitest # Run all tests (watch mode)
vitest run # Run once (CI mode)
vitest --coverage # Generate coverage report (≥85% required)
vitest --ui # Interactive UI
vitest tests/unit/calculator.test.ts # Run specific test
2. Code Quality (Biome 1.9+)
Why Biome over ESLint + Prettier?
- ⚡ 75x faster than ESLint
- 🔧 Single tool (linting + formatting)
- ✅ TypeScript-first design
- 🎯 Zero dependencies (Rust-based)
Configuration (biome.json):
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noExcessiveCognitiveComplexity": {
"level": "error",
"options": {
"maxAllowedComplexity": 10
}
}
},
"style": {
"useConst": "error",
"noVar": "error"
}
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": {
"quoteStyle": "single",
"semicolons": "always"
}
}
}
CLI Commands:
biome check . # Lint + format check
biome check --write . # Lint + format with auto-fix
biome format --write . # Format only
biome lint . # Lint only
3. Type Safety (TypeScript 5.7+ Strict Mode)
tsconfig.json (strict configuration):
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*", "tests/**/*"],
"exclude": ["node_modules", "dist"]
}
Advanced Type Patterns:
// Type-safe API response
type ApiResponse<T> =
| { success: true; data: T }
| { success: false; error: string };
// Generic with constraints
function filterItems<T extends { id: number }>(
items: T[],
predicate: (item: T) => boolean
): T[] {
return items.filter(predicate);
}
// Const type parameters (TypeScript 5.7)
function createSet<const T extends readonly unknown[]>(
...items: T
): Set<T[number]> {
return new Set(items);
}
// Satisfies operator (TypeScript 5.7)
const config = {
endpoint: '/api/users',
timeout: 5000,
} satisfies Record<string, string | number>;
CLI Commands:
tsc --noEmit # Type check without output
tsc --noEmit --watch # Type check in watch mode
tsc --build # Build project
4. Package Management
Recommended: Use pnpm for faster installs and disk efficiency.
Setup:
# Install pnpm
npm install -g pnpm
# Initialize project
pnpm init
# Install dependencies
pnpm add typescript vitest @vitest/ui @biomejs/biome
pnpm add -D @types/node
# Install framework dependencies (React/Next.js)
pnpm add react react-dom next
pnpm add -D @types/react @types/react-dom
Alternative: Bun (fastest runtime + package manager):
# Install Bun
curl -fsSL https://bun.sh/install | bash
# Initialize project
bun init
# Install dependencies
bun add typescript vitest @biomejs/biome
5. React/Next.js Patterns
Type-safe React Component:
// src/components/UserCard.tsx
import { type FC } from 'react';
interface UserCardProps {
name: string;
email: string;
age?: number;
}
export const UserCard: FC<UserCardProps> = ({ name, email, age }) => {
return (
<div className="user-card">
<h2>{name}</h2>
<p>{email}</p>
{age !== undefined && <p>Age: {age}</p>}
</div>
);
};
Next.js Server Action (TypeScript 5.7):
// app/actions/user.ts
'use server';
import { z } from 'zod';
const userSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
});
export async function createUser(formData: FormData): Promise<ApiResponse<{ id: number }>> {
const data = {
name: formData.get('name'),
email: formData.get('email'),
};
const validation = userSchema.safeParse(data);
if (!validation.success) {
return { success: false, error: validation.error.message };
}
// Save to database...
return { success: true, data: { id: 1 } };
}
6. Security Best Practices
Input Validation (Zod):
import { z } from 'zod';
const userInputSchema = z.object({
username: z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/),
email: z.string().email(),
age: z.number().int().min(13).max(120),
});
type UserInput = z.infer<typeof userInputSchema>;
function validateUserInput(data: unknown): UserInput {
return userInputSchema.parse(data); // Throws if invalid
}
Environment Variables (type-safe):
// src/env.ts
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
API_KEY: z.string().min(32),
NODE_ENV: z.enum(['development', 'production', 'test']),
});
export const env = envSchema.parse(process.env);
7. React Error Boundaries (Production Must-Have)
Why Error Boundaries?
- ✅ Catch runtime errors in React component tree
- ✅ Prevent app crash from a single component error
- ✅ Show fallback UI instead of blank page
- ✅ Log errors to monitoring services (Sentry, DataDog)
Error Boundary Class Component:
// src/components/ErrorBoundary.tsx
import { Component, type ReactNode } from 'react';
interface Props {
children: ReactNode;
fallback?: ReactNode;
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
}
interface State {
hasError: boolean;
error?: Error;
}
export class ErrorBoundary extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): State {
// Update state so next render shows fallback UI
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// Log error to error tracking service
console.error('ErrorBoundary caught:', error, errorInfo);
// Call custom error handler
this.props.onError?.(error, errorInfo);
// Example: Send to Sentry
// Sentry.captureException(error, { extra: errorInfo });
}
render() {
if (this.state.hasError) {
// Render fallback UI
return (
this.props.fallback ?? (
<div className="error-container">
<h1>Something went wrong</h1>
<p>{this.state.error?.message}</p>
<button onClick={() => this.setState({ hasError: false })}>
Try again
</button>
</div>
)
);
}
return this.props.children;
}
}
Usage in App:
// app/layout.tsx (Next.js App Router)
import { ErrorBoundary } from '@/components/ErrorBoundary';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>
<ErrorBoundary fallback={<ErrorFallback />}>
{children}
</ErrorBoundary>
</body>
</html>
);
}
// Custom fallback component
function ErrorFallback() {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<h1 className="text-2xl font-bold">Oops! Something went wrong</h1>
<p className="mt-4">We're working on fixing this issue.</p>
<button
onClick={() => window.location.reload()}
className="mt-6 px-4 py-2 bg-blue-500 text-white rounded"
>
Reload page
</button>
</div>
</div>
);
}
Multiple Error Boundaries (granular error handling):
// app/dashboard/page.tsx
import { ErrorBoundary } from '@/components/ErrorBoundary';
export default function DashboardPage() {
return (
<div>
<h1>Dashboard</h1>
{/* Separate error boundary for each section */}
<ErrorBoundary fallback={<div>Failed to load stats</div>}>
<StatsWidget />
</ErrorBoundary>
<ErrorBoundary fallback={<div>Failed to load chart</div>}>
<ChartWidget />
</ErrorBoundary>
<ErrorBoundary fallback={<div>Failed to load table</div>}>
<DataTable />
</ErrorBoundary>
</div>
);
}
Next.js 15 App Router Alternative (error.tsx):
// app/error.tsx
'use client'; // Error components must be Client Components
import { useEffect } from 'react';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Log error to error reporting service
console.error('App error:', error);
}, [error]);
return (
<div className="flex flex-col items-center justify-center min-h-screen">
<h2 className="text-2xl font-bold">Something went wrong!</h2>
<p className="mt-2 text-gray-600">{error.message}</p>
<button
onClick={reset}
className="mt-4 px-4 py-2 bg-blue-500 text-white rounded"
>
Try again
</button>
</div>
);
}
Global error handler (app/global-error.tsx):
// app/global-error.tsx
'use client';
export default function GlobalError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html>
<body>
<h2>Global Error: Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</body>
</html>
);
}
Testing Error Boundaries:
// tests/unit/ErrorBoundary.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import { ErrorBoundary } from '@/components/ErrorBoundary';
function ThrowError() {
throw new Error('Test error');
}
describe('ErrorBoundary', () => {
it('should catch errors and show fallback', () => {
// Suppress console.error for this test
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
render(
<ErrorBoundary fallback={<div>Error occurred</div>}>
<ThrowError />
</ErrorBoundary>
);
expect(screen.getByText('Error occurred')).toBeDefined();
consoleSpy.mockRestore();
});
it('should call onError handler', () => {
const onError = vi.fn();
render(
<ErrorBoundary onError={onError}>
<ThrowError />
</ErrorBoundary>
);
expect(onError).toHaveBeenCalled();
});
it('should recover after error', async () => {
const { rerender } = render(
<ErrorBoundary>
<ThrowError />
</ErrorBoundary>
);
expect(screen.getByText('Something went wrong')).toBeDefined();
// Rerender with valid component
rerender(
<ErrorBoundary>
<div>Success</div>
</ErrorBoundary>
);
// Error boundary should reset
expect(screen.getByText('Success')).toBeDefined();
});
});
Integration with Error Monitoring (Sentry example):
// src/lib/error-tracking.ts
import * as Sentry from '@sentry/nextjs';
export function initErrorTracking() {
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 1.0,
});
}
// src/components/ErrorBoundary.tsx (enhanced)
export class ErrorBoundary extends Component<Props, State> {
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
// Send to Sentry with additional context
Sentry.captureException(error, {
contexts: {
react: {
componentStack: errorInfo.componentStack,
},
},
});
this.props.onError?.(error, errorInfo);
}
}
TypeScript 5.7 New Features
Const Type Parameters
// Infer exact literal types
function createTuple<const T extends readonly unknown[]>(...items: T): T {
return items;
}
const tuple = createTuple(1, 'hello', true);
// Type: readonly [1, 'hello', true] (not number | string | boolean)
Satisfies Operator
// Type check without widening
const routes = {
home: '/',
about: '/about',
contact: '/contact',
} satisfies Record<string, string>;
// routes.home is typed as '/' (not string)
Constitution Compliance
My-Spec Requirements:
- ✅ Files ≤500 SLOC (split if larger)
- ✅ Functions ≤100 lines
- ✅ Complexity ≤10 per function
- ✅ Test coverage ≥85%
- ✅ Strict typing enabled
- ✅ TAG blocks in all files
File Size Check:
# Count SLOC (excluding comments/blank lines)
cloc src/components/UserCard.tsx --by-file
Complexity Check:
# Biome checks complexity automatically
biome check . --max-diagnostics=0
Tool Version Matrix (2025-10-26)
| Tool | Version | Purpose | Status |
|---|---|---|---|
| TypeScript | 5.7.2 | Primary | ✅ Latest |
| Vitest | 2.1.0 | Testing | ✅ Current |
| Biome | 1.9.4 | Lint/Format | ✅ Current |
| pnpm | 9.14.2 | Package mgmt | ✅ Recommended |
| Bun | 1.1.0 | Runtime | ✅ Alternative |
| React | 19.0.0 | UI Library | ✅ Latest |
| Next.js | 15.1.0 | Framework | ✅ Latest |
Example Workflow
Setup (pnpm + TypeScript 5.7):
pnpm init
pnpm add typescript vitest @biomejs/biome
pnpm add -D @types/node
# Create tsconfig.json
npx tsc --init --strict
TDD Loop:
vitest # RED: Watch tests fail
# [implement code]
vitest # GREEN: Watch tests pass
biome check --write . # REFACTOR: Fix code quality
Quality Gate (before commit):
vitest run --coverage # Coverage ≥85%?
biome check . # Lint pass?
tsc --noEmit # Type check pass?
Best Practices
✅ DO:
- Use Vitest for all tests (not Jest)
- Enable TypeScript strict mode
- Use Biome for linting + formatting (not ESLint + Prettier)
- Specify exact TypeScript version in package.json
- Run quality gate before each commit
- Use const assertions and satisfies operator
- Add type annotations to public APIs
- Keep files ≤500 SLOC (Constitution requirement)
❌ DON'T:
- Use Jest (Vitest is faster and better for TS)
- Use ESLint + Prettier (Biome replaces both)
- Use
anytype (useunknowninstead) - Ignore type errors (fix them or use explicit
@ts-expect-error) - Mix testing frameworks
- Skip coverage requirements (<85% fails)
- Use old TypeScript syntax (upgrade to 5.7+)
Integration with My-Spec
TAG Block Format (TypeScript):
/**
* @CODE:AUTH-001
* @SPEC: specs/001-auth-spec/spec.md
* @TEST: tests/unit/auth.test.ts
* @CHAIN: @SPEC:AUTH-001 → @TEST:AUTH-001 → @CODE:AUTH-001
* @STATUS: implemented
* @CREATED: 2025-10-26
* @UPDATED: 2025-10-26
*/
export class AuthService {
// Implementation...
}
Test TAG Block:
/**
* @TEST:AUTH-001
* @SPEC: specs/001-auth-spec/spec.md
* @CODE: src/services/auth.ts
* @CHAIN: @SPEC:AUTH-001 → @TEST:AUTH-001 → @CODE:AUTH-001
* @STATUS: passing
*/
describe('AuthService', () => {
// Tests...
});
References (Latest Documentation)
- TypeScript 5.7: https://www.typescriptlang.org/docs/ (accessed 2025-10-26)
- Vitest 2.1: https://vitest.dev/ (accessed 2025-10-26)
- Biome 1.9: https://biomejs.dev/ (accessed 2025-10-26)
- pnpm: https://pnpm.io/ (accessed 2025-10-26)
- React 19: https://react.dev/ (accessed 2025-10-26)
- Next.js 15: https://nextjs.org/docs (accessed 2025-10-26)
Changelog
- v1.0.0 (2025-10-26): Initial TypeScript Skill for My-Spec workflow with Vitest 2.1, Biome 1.9, TypeScript 5.7, Constitution compliance
Works Well With
ms-foundation-trust(TRUST 5 validation)ms-foundation-constitution(file size/complexity checks)ms-workflow-tag-manager(TAG block generation)ms-workflow-living-docs(API documentation sync)