Skip to content

Instantly share code, notes, and snippets.

@electricessence
Created June 11, 2025 22:02
Show Gist options
  • Save electricessence/ab39f44537e5002c1f22bcd759f24276 to your computer and use it in GitHub Desktop.
Save electricessence/ab39f44537e5002c1f22bcd759f24276 to your computer and use it in GitHub Desktop.
Style and Design Guide for AI-Generated TypeScript

Copilot Instructions: TypeScript Style and Design Guide

This file guides AI and human contributors in writing clean, modern TypeScript code. It reflects best practices as of 2025, aligned with our team’s priorities.


🧠 Core Principles

  • Readability above all else: Code must be easy to follow, even by new contributors or AI tools.
  • Concise and clean: Prefer clarity over cleverness. Avoid unnecessary abstraction.
  • Modular and testable: Keep functions focused, side-effect-free, and easy to test.
  • Functional where helpful: Use map, filter, reduce, and similar constructs when they simplify logic.
  • Inline documentation: Use comments and JSDoc to explain purpose, especially for non-obvious logic.

🛠 Best Practices (2025 Edition)

  • Use strict: true in tsconfig.json.
  • Prefer type for unions and compositions; use interface for objects with inheritance or extension.
  • Use satisfies to validate structure while preserving literal types.
  • Use as const for immutable literals.
  • Avoid default exports; prefer named exports for clarity.
  • Group imports: Node/standard → external packages → internal modules.
  • Structure files by feature or domain, not by technical type (e.g., "components", "utils").
  • Use readonly modifiers on objects and arrays to protect data integrity.
  • Always handle switch cases exhaustively with a never fallback.
  • Avoid global state or singleton patterns—inject dependencies explicitly.
  • Keep function bodies flat and under 30 lines when possible.
  • Avoid using any. Use unknown with explicit type narrowing if needed.

🧰 Tooling Standards

  • Use pnpm as the package manager for speed and efficiency.
  • Lint code using ESLint with:
    • @typescript-eslint/eslint-plugin
    • eslint:recommended
    • plugin:@typescript-eslint/recommended
  • Format code with Prettier, but separate from linting responsibilities.
  • Add type packages (@types/*) as devDependencies when working with untyped libraries.
  • Use a types/ directory for global types or overrides.
  • Enable modern ESM support via "module": "NodeNext" or "module": "ESNext" in tsconfig.

🔍 Advanced Language Features

  • Template literal types for expressive string contracts and mapped keys.
  • Variadic tuple types to support flexible argument patterns.
  • Conditional types with infer to derive or transform types safely.
  • Mapped types to transform shapes dynamically.
  • Utility types: Use built-ins (Pick, Omit, Partial, Readonly, ReturnType, Parameters) and custom ones as needed.
  • Use runtime schema validation with zod, valibot, or io-ts when accepting dynamic input (API responses, config files).
  • Prefer composition over inheritance in all but the most necessary cases.
  • When adopting functional patterns (e.g., with remeda, effect, or fp-ts), always pair them with clear names and type annotations.

✅ PR Checklist

  • Code is readable and logically structured.
  • Variable and function names are descriptive and intention-revealing.
  • Modules are well-scoped (ideally under 200 lines).
  • Every exported function includes a JSDoc block.
  • Type safety is preserved (no any; unknown is narrowed).
  • All runtime inputs are validated or sanitized.
  • Lint and type checks pass cleanly.
  • Unit tests cover new logic and edge cases.

🤖 AI-Specific Instructions

If you're using an AI to assist in writing code, ensure it follows these guidelines:

  • Explain complex logic with comments.
  • Default to small, composable functions.
  • Prefer explicit return types on exported functions.
  • Avoid overgeneralizing or generating “magic” code.
  • Document assumptions about data shape or behavior.

Got it. Here's the ESLint and TypeScript config added as markdown-embedded code blocks, ready to append to the bottom of your copilot.md:


🧩 Recommended ESLint Configuration

// .eslintrc.cjs
module.exports = {
  root: true,
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier',
  ],
  env: {
    node: true,
    es2022: true,
  },
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  rules: {
    '@typescript-eslint/explicit-function-return-type': ['warn', { allowExpressions: true }],
    '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/consistent-type-imports': 'warn',
    'no-console': 'warn',
  },
};

🧩 Recommended tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ES2022", "DOM"],
    "strict": true,
    "noImplicitOverride": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "forceConsistentCasingInFileNames": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "allowSyntheticDefaultImports": true,
    "declaration": true,
    "outDir": "dist",
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  },
  "include": ["src"],
  "exclude": ["node_modules", "dist"]
}

🧩 Recommended ESLint Configuration

// .eslintrc.cjs
module.exports = {
  root: true,
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier',
  ],
  env: {
    node: true,
    es2022: true,
  },
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  rules: {
    '@typescript-eslint/explicit-function-return-type': ['warn', { allowExpressions: true }],
    '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/consistent-type-imports': 'warn',
    'no-console': 'warn',
  },
};

🧪 Suggested package.json Dev Scripts

{
  "scripts": {
    "dev": "tsx src/index.ts",
    "build": "tsc --build",
    "typecheck": "tsc --noEmit",
    "lint": "eslint . --ext .ts,.tsx",
    "fix": "eslint . --ext .ts,.tsx --fix",
    "clean": "rm -rf dist",
    "start": "node dist/index.js",
    "test": "vitest run",
    "test:watch": "vitest"
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment