--- id: alinaqi/maggy/typescript version: "83fc11dc" license: MIT install: manual updated: 2026-07-14 --- # typescript — This skill establishes a TypeScript development environment with strict compiler options, ESLint rules, and Jest test coverage. It provides project structure templates, tooling configuration, and GitHub Actions workflows to maintain code quality and type safety across your codebase. Publisher: alinaqi · Stars: 703 · Updated: 2026-07-14 Install (manual): `git clone https://github.com/alinaqi/maggy` ## SKILL.md # TypeScript Skill --- ## Strict Mode (Non-Negotiable) ```json // tsconfig.json { "compilerOptions": { "strict": true, "noImplicitAny": true, "strictNullChecks": true, "noUnusedLocals": true, "noUnusedParameters": true, "noImplicitReturns": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true } } ``` --- ## Project Structure ``` project/ ├── src/ │ ├── core/ # Pure business logic │ │ ├── types.ts # Domain types/interfaces │ │ ├── services/ # Pure functions │ │ └── index.ts # Public API │ ├── infra/ # Side effects │ │ ├── api/ # HTTP handlers │ │ ├── db/ # Database operations │ │ └── external/ # Third-party integrations │ └── utils/ # Shared utilities ├── tests/ │ ├── unit/ │ └── integration/ ├── package.json ├── tsconfig.json └── CLAUDE.md ``` --- ## Tooling (Required) ```json // package.json scripts { "scripts": { "lint": "eslint src/ --ext .ts,.tsx", "typecheck": "tsc --noEmit", "test": "jest", "test:coverage": "jest --coverage", "format": "prettier --write 'src/**/*.ts'" } } ``` ```javascript // eslint.config.js import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; export default tseslint.config( eslint.configs.recommended, ...tseslint.configs.strictTypeChecked, { rules: { '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/explicit-function-return-type': 'error', 'max-lines-per-function': ['error', 20], 'max-depth': ['error', 2], 'max-params': ['error', 3], } } ); ``` --- ## Testing with Jest ```typescript // tests/unit/services/user.test.ts import { calculateTotal } from '../../../src/core/services/pricing'; describe('calculateTotal', () => { it('returns sum of item prices', () => { // Arrange const items = [{ price: 10 }, { price: 20 }]; // Act const result = calculateTotal(items); // Assert expect(result).toBe(30); }); it('returns zero for empty array', () => { expect(calculateTotal([])).toBe(0); }); it('throws on invalid item', () => { expect(() => calculateTotal([{ invalid: 'item' }])).toThrow(); }); }); ``` --- ## GitHub Actions ```yaml name: TypeScript Quality Gate on: [push, pull_request] jobs: quality: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Lint run: npm run lint - name: Type Check run: npm run typecheck - name: Test with Coverage run: npm run test:coverage - name: Coverage Threshold (80%) run: npm run test:coverage -- --coverageThreshold='{"global":{"branches":80,"functions":80,"lines":80,"statements":80}}' ``` --- ## Pre-Commit Hooks Using Husky + lint-staged: ```bash npm install -D husky lint-staged npx husky init ``` ```json // package.json { "lint-staged": { "*.{ts,tsx}": [ "eslint --fix", "prettier --write" ] } } ``` ```bash # .husky/pre-commit npx lint-staged npx tsc --noEmit npm run test -- --onlyChanged --passWithNoTests ``` This runs on every commit: 1. ESLint + Prettier on staged files 2. Type check entire project 3. Tests for changed files only --- ## Type Patterns ### Discriminated Unions for Results ```typescript type Result = | { ok: true; value: T } | { ok: false; error: string }; function parseUser(data: unknown): Result { // Type-safe error handling without exceptions } ``` ### Branded Types for IDs ```typescript type UserId = string & { readonly brand: unique symbol }; type OrderId = string & { readonly brand: unique symbol }; // Can't accidentally pass UserId where OrderId expected function getOrder(orderId: OrderId): Order { ... } ``` ### Const Assertions for Literals ```typescript const STATUSES = ['pending', 'active', 'closed'] as const; type Status = typeof STATUSES[number]; // 'pending' | 'active' | 'closed' ``` ### Zod for Runtime Validation ```typescript import { z } from 'zod'; const UserSchema = z.object({ email: z.string().email(), name: z.string().min(1).max(100), }); type User = z.infer; ``` --- ## TypeScript Anti-Patterns - ❌ `any` type - use `unknown` and narrow - ❌ Type assertions (`as`) - use type guards - ❌ Non-null assertions (`!`) - handle null explicitly - ❌ `@ts-ignore` without explanation - ❌ Enums - use const objects or union types - ❌ Classes for data - use interfaces/types - ❌ Default exports - use named exports [View on SkillFed](https://skillfed.io/alinaqi/maggy/typescript) · [View on GitHub](https://github.com/alinaqi/maggy)