Skip to main content
skill CX Codex

typescript · alinaqi — Claude Code skill: strict mode, eslint, jest

Tells the agent how to write and check TypeScript: strict tsconfig, ESLint config, Jest tests and a layered project layout. Kicks in on .ts and .tsx files.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add alinaqi/maggy --skill typescript -a claude-code
Open on GitHub

What typescript does

The skill activates on its own when the agent touches files matching **/*.ts, **/*.tsx or tsconfig*.json. Inside is a ready tsconfig.json with strict, noImplicitAny, strictNullChecks, noUnusedLocals, noUnusedParameters, noImplicitReturns and esModuleInterop. Alongside it sits an eslint.config.js built on typescript-eslint with strict rules: no any, explicit return types, a 20-line cap per function, max depth 2 and at most 3 parameters.

Project layout is spelled out too: src/core for pure logic, src/infra for side effects, tests/unit and tests/integration. A Jest example shows the Arrange/Act/Assert split. There is a GitHub Actions workflow running lint, typecheck and test:coverage, with the coverage threshold set to 80% for branches, functions, lines and statements. Commits go through Husky and lint-staged: ESLint with --fix, Prettier, then tsc --noEmit and tests limited to changed files.

The rules are strict. any, as assertions, the ! operator, unexplained @ts-ignore and enums are all listed as anti-patterns. If your codebase relies on enums on purpose, or any is scattered through legacy code, the agent will push back against what is already there. Worth checking before you install the whole thing.

What it helps with

  • turn on strict TypeScript in a fresh project
  • split code into core, infra and utils layers
  • set up ESLint with type-aware rules
  • add Jest tests with a coverage gate
  • run checks on every commit via Husky

Example prompts for the agent

  • Set up tsconfig.json following the typescript skill rules
  • Write a Jest test for calculateTotal using Arrange/Act/Assert
  • Check this file for TypeScript anti-patterns and replace any

How to install typescript

1Skills CLI (Vercel)

npx skills add alinaqi/maggy --skill typescript -a claude-code

2Manually: put the files in place

~/.claude/skills/typescript/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/typescript/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about typescript

How do I install the typescript skill in Claude?

Run npx skills add alinaqi/maggy --skill typescript -a claude-code. The skill lands at ~/.claude/skills/typescript/SKILL.md.

What does the typescript skill do?

It gives the agent a working set of TypeScript conventions: strict tsconfig, an ESLint config, Jest tests, a directory layout and pre-commit hooks.

When does the skill trigger?

It is bound to **/*.ts, **/*.tsx and tsconfig*.json, so it fires when the agent works with those files. There is no manual invocation.

Source text

SKILL.md · MIT
---
name: typescript
description: TypeScript strict mode with eslint and jest
when-to-use: When working on TypeScript files
user-invocable: false
paths: ["**/*.ts", "**/*.tsx", "tsconfig*.json"]
effort: medium
---

# 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<T> =
  | { ok: true; value: T }
  | { ok: false; error: string };

function parseUser(data: unknown): Result<User> {
  // 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<typeof UserSchema>;
```

---

## 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

© alinaqi · MIT · alinaqi/maggy

Similar skills

All skills for Programming languages →

typescript by other authors comes first.

typescript gentleman-programming A skill that hands your agent a fixed set of strict TypeScript rules: const objects instead of union types, flat interfaces, no any. Useful when AI writes the code and you want one style. CX Codex +1 496installs typescript PyModel A skill with 44 rules on types, tsconfig and async code. Useful when your agent edits compiler config or untangles heavy generics. CX Codex +1 520installs typescript Mindrally Enforces strict TypeScript standards and functional code patterns in your AI assistant. It bans any, replaces enums with maps, and caps function length at 20 lines. CX Codex +1 955installs typescript-pro https://github.com/Jeffallan Implements advanced TypeScript type systems, branded types, and tRPC configurations. Use it when building type-first APIs or complex discriminated unions. CX Codex +1 14,200installs typescript-discriminated-unions mkosir Guides coding agents to apply discriminated unions in TypeScript, eliminating invalid states and enabling exhaustiveness checks. CX Codex +1 3,800installs ui5-typescript-conversion cline A skill that walks a SAPUI5 or OpenUI5 project through a TypeScript conversion: build setup, types, then the code itself. Useful when a JS project needs typing. CX Codex +1 910installs typescript-core bobmatnyc A skill with modern TypeScript patterns: a strict tsconfig, runtime validation, advanced types. Useful once a TS codebase outgrows its type setup. CX Codex +1 475installs fastify-typescript Mindrally Gives the agent a rulebook for Fastify and TypeScript: validation schemas, plugins, Prisma access and Jest tests. Useful when you build a typed REST API. CX Codex +1 856installs

From the same set32

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor