Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save kaznak/e9d9f3d8792afc6a9d7abbadff25b3b5 to your computer and use it in GitHub Desktop.

Select an option

Save kaznak/e9d9f3d8792afc6a9d7abbadff25b3b5 to your computer and use it in GitHub Desktop.

Revisions

  1. @mizchi mizchi revised this gist Jun 10, 2025. No changes.
  2. @mizchi mizchi revised this gist Jun 10, 2025. No changes.
  3. @mizchi mizchi revised this gist Jun 10, 2025. No changes.
  4. @mizchi mizchi revised this gist Jun 10, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion typescript-project-setup-guide.md
    Original file line number Diff line number Diff line change
    @@ -72,7 +72,7 @@ import { defineConfig } from "vitest/config";
    export default defineConfig({
    test: {
    includeSource: ["src/**/*.{ts}"],
    include: ["src/**/*.{test,spec}.{ts,tsx}"],
    include: ["src/**/*.{test,spec}.{ts}"],
    },
    });
    ```
  5. @mizchi mizchi revised this gist Jun 10, 2025. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion typescript-project-setup-guide.md
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,6 @@ package.json
    "devDependencies": {
    "@types/node": "^24.0.0",
    "@vitest/coverage-v8": "3.2.3",
    "jiti": "^2.4.2",
    "typescript": "^5.8.3",
    "vitest": "^3.2.3"
    },
  6. @mizchi mizchi revised this gist Jun 10, 2025. 1 changed file with 1 addition and 2 deletions.
    3 changes: 1 addition & 2 deletions typescript-project-setup-guide.md
    Original file line number Diff line number Diff line change
    @@ -11,8 +11,7 @@ Always setup baseline settings
    ```bash
    pnpm init --init-type module
    pnpm add typescript vitest @vitest/coverage-v8 @types/node -D
    echo "{}" > .vscode/settings.json
    echo "node_modules\ntmp" > .gitignore
    echo "node_modules\ntmp\ncoverage" > .gitignore
    mkdir -p src

    # git
  7. @mizchi mizchi revised this gist Jun 10, 2025. No changes.
  8. @mizchi mizchi revised this gist Jun 10, 2025. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion typescript-project-setup-guide.md
    Original file line number Diff line number Diff line change
    @@ -241,7 +241,7 @@ CLAUDE.md
    ## Optional: neverthrow

    ```bash
    pnpm add neverthrow -D
    pnpm add neverthrow
    ```

    Additional prompt
  9. @mizchi mizchi created this gist Jun 10, 2025.
    251 changes: 251 additions & 0 deletions typescript-project-setup-guide.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,251 @@
    This is typescript environment setup guide for LLM and humans

    ## Baseline

    Always setup baseline settings

    - pnpm
    - typescript
    - vitest

    ```bash
    pnpm init --init-type module
    pnpm add typescript vitest @vitest/coverage-v8 @types/node -D
    echo "{}" > .vscode/settings.json
    echo "node_modules\ntmp" > .gitignore
    mkdir -p src

    # git
    git init
    git add .
    git commit -m "init"
    ```

    package.json

    ```json
    {
    "private": true,
    "type": "module",
    "scripts": {
    "typecheck": "tsc --noEmit",
    "test": "vitest run",
    "test:cov": "vitest run --coverage"
    },
    "license": "MIT",
    "devDependencies": {
    "@types/node": "^24.0.0",
    "@vitest/coverage-v8": "3.2.3",
    "jiti": "^2.4.2",
    "typescript": "^5.8.3",
    "vitest": "^3.2.3"
    },
    "pnpm": {
    "onlyBuiltDependencies": ["esbuild"]
    }
    }
    ```

    tsconfig.json

    ```json
    {
    "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "bundler",
    "noEmit": true,
    "esModuleInterop": true,
    "allowImportingTsExtensions": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "types": ["vitest/importMeta"]
    }
    }
    ```

    or `pnpm tsc --init --module esnext --moduleResolution Bundler --target esnext --noEmit`

    vitest.config.ts

    ```ts
    import { defineConfig } from "vitest/config";
    export default defineConfig({
    test: {
    includeSource: ["src/**/*.{ts}"],
    include: ["src/**/*.{test,spec}.{ts,tsx}"],
    },
    });
    ```

    Entrypoint: src/index.ts

    ```ts
    /**
    * explation of this module
    */
    export {};
    if (import.meta.vitest) {
    const { test, expect } = import.meta.vitest;
    test("init", () => {
    expect(true).toBe(true);
    });
    }
    ```

    .github/workflows/ci.yaml

    ```yaml
    name: CI
    on:
    push:
    branches: [main]
    pull_request:
    branches: [main]
    jobs:
    test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Install pnpm
    uses: pnpm/action-setup@v4
    with:
    version: 10
    - uses: actions/setup-node@v4
    with:
    node-version: 24
    cache: "pnpm"
    - run: pnpm install --frozen-lockfile
    - run: pnpm test
    - run: pnpm typecheck
    ```
    ## Optional: eslint
    Ask to user: `Do you want to use eslint?`

    ```bash
    pnpm add -d @eslint/js eslint typescript-eslint
    ```

    package.json

    ```json
    {
    "scripts": {
    "lint": "eslint . --quiet",
    "lint:warn": "eslint .",
    "lint:fix": "eslint . --fix"
    }
    }
    ```

    eslint.config.ts

    ```ts
    import eslint from "@eslint/js";
    import tseslint from "typescript-eslint";
    export default tseslint.config(
    eslint.configs.recommended,
    ...tseslint.configs.recommendedTypeCheckedOnly,
    {
    languageOptions: {
    parserOptions: {
    projectService: true,
    tsconfigRootDir: import.meta.dirname,
    },
    },
    },
    {
    // base rules
    rules: {
    "@typescript-eslint/no-redeclare": "error",
    "@typescript-eslint/prefer-ts-expect-error": "error",
    "@typescript-eslint/no-floating-promises": "error",
    "@typescript-eslint/only-throw-error": "error",
    "no-throw-literal": "off",
    },
    },
    {
    // warning for refactoring
    rules: {
    "@typescript-eslint/no-empty-interface": "warn",
    "@typescript-eslint/no-empty-object-type": "warn",
    "@typescript-eslint/no-empty-function": "warn",
    "@typescript-eslint/no-explicit-any": "warn",
    "@typescript-eslint/no-deprecated": "warn",
    "@typescript-eslint/await-thenable": "warn",
    "@typescript-eslint/require-await": "warn",
    "@typescript-eslint/consistent-type-imports": [
    "warn",
    {
    prefer: "type-imports",
    disallowTypeAnnotations: false,
    fixStyle: "inline-type-imports",
    },
    ],
    "@typescript-eslint/ban-ts-comment": [
    "warn",
    {
    "ts-ignore": true,
    "ts-expect-error": "allow-with-description",
    },
    ],
    "prefer-const": "warn",
    complexity: ["warn", { max: 7 }],
    "no-console": "warn",
    },
    },
    {
    // allow console in examples
    files: ["examples/*.ts"],
    rules: {
    "no-console": "off",
    },
    }
    );
    ```

    ## Optional: PROMPT

    CLAUDE.md

    ```markdown
    ## Coding Rules
    - File covention: `src/<snake_case>.ts`
    - Add test `src/*.test.ts` for `src/*.ts`
    - Use function and function scope instead of class
    - Add `.ts` extensions to import. eg. `import {} from "./x.ts"` for deno compatibility.
    - Never disable any lint rules without explicit user approval
    ```
    .claude/settings.json
    ```json
    {
    "permissions": {
    "allow": ["Bash(pnpm test)", "Bash(ls:*)", "Bash(grep:*)"],
    "deny": []
    }
    }
    ```

    .mcp.json

    ```
    {}
    ```

    ## Optional: neverthrow

    ```bash
    pnpm add neverthrow -D
    ```

    Additional prompt

    ```
    Never throw exception in our project. Instead of throw, use neverthrow
    ```