claude-toolkit 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +126 -0
  4. package/bin/cli.ts +112 -0
  5. package/core/agents/ct-code-reviewer.md +123 -0
  6. package/core/agents/ct-github-workflow.md +137 -0
  7. package/core/commands/ct/code-quality.md +59 -0
  8. package/core/commands/ct/onboard.md +84 -0
  9. package/core/commands/ct/pr-review.md +104 -0
  10. package/core/commands/ct/pr-summary.md +59 -0
  11. package/core/commands/ct/proto-check.md +74 -0
  12. package/core/commands/ct/ticket.md +71 -0
  13. package/core/hooks/skill-eval.js +381 -0
  14. package/core/hooks/skill-eval.sh +35 -0
  15. package/core/hooks/skill-rules.schema.json +112 -0
  16. package/core/skills/systematic-debugging/SKILL.md +44 -0
  17. package/core/skills/testing-patterns/SKILL.md +52 -0
  18. package/core/skills/typescript-conventions/SKILL.md +57 -0
  19. package/core/skills/verification-before-completion/SKILL.md +42 -0
  20. package/docs/README.md +49 -0
  21. package/docs/agents/code-reviewer.md +76 -0
  22. package/docs/agents/github-workflow.md +98 -0
  23. package/docs/best-practices/solidjs/README.md +43 -0
  24. package/docs/best-practices/solidjs/anti-patterns.md +166 -0
  25. package/docs/best-practices/solidjs/component-patterns.md +131 -0
  26. package/docs/best-practices/solidjs/context-and-global-state.md +131 -0
  27. package/docs/best-practices/solidjs/control-flow.md +124 -0
  28. package/docs/best-practices/solidjs/data-fetching.md +205 -0
  29. package/docs/best-practices/solidjs/effects-and-lifecycle.md +113 -0
  30. package/docs/best-practices/solidjs/performance.md +100 -0
  31. package/docs/best-practices/solidjs/props-patterns.md +100 -0
  32. package/docs/best-practices/solidjs/reactivity-model.md +104 -0
  33. package/docs/best-practices/solidjs/signals-and-state.md +78 -0
  34. package/docs/best-practices/solidjs/stores-and-nested-state.md +111 -0
  35. package/docs/best-practices/solidjs/typescript-integration.md +186 -0
  36. package/docs/best-practices/typescript/README.md +45 -0
  37. package/docs/best-practices/typescript/any-and-unknown.md +73 -0
  38. package/docs/best-practices/typescript/deriving-vs-decoupling.md +83 -0
  39. package/docs/best-practices/typescript/discriminated-unions.md +75 -0
  40. package/docs/best-practices/typescript/enums-alternatives.md +72 -0
  41. package/docs/best-practices/typescript/essential-patterns.md +119 -0
  42. package/docs/best-practices/typescript/generics-patterns.md +105 -0
  43. package/docs/best-practices/typescript/micro-opinions.md +87 -0
  44. package/docs/best-practices/typescript/runtime-validation.md +62 -0
  45. package/docs/best-practices/typescript/satisfies-operator.md +100 -0
  46. package/docs/best-practices/typescript/tsconfig-cheat-sheet.md +129 -0
  47. package/docs/best-practices/typescript/type-organization.md +64 -0
  48. package/docs/best-practices/typescript/type-vs-interface.md +80 -0
  49. package/docs/commands/code-quality.md +42 -0
  50. package/docs/commands/onboard.md +72 -0
  51. package/docs/commands/pr-review.md +102 -0
  52. package/docs/commands/pr-summary.md +50 -0
  53. package/docs/commands/proto-check.md +59 -0
  54. package/docs/commands/ticket.md +56 -0
  55. package/docs/skills/systematic-debugging.md +70 -0
  56. package/docs/skills/testing-patterns.md +89 -0
  57. package/docs/skills/typescript-conventions.md +137 -0
  58. package/docs/skills/verification-before-completion.md +91 -0
  59. package/docs/stacks/cloudflare-d1-kv.md +110 -0
  60. package/docs/stacks/i18n-typesafe.md +141 -0
  61. package/docs/stacks/protobuf-contracts.md +85 -0
  62. package/docs/stacks/rust-wasm-patterns.md +106 -0
  63. package/docs/stacks/solidjs-patterns.md +110 -0
  64. package/docs/stacks/vanilla-extract-patterns.md +115 -0
  65. package/package.json +58 -0
  66. package/src/generator.ts +317 -0
  67. package/src/index.ts +30 -0
  68. package/src/types.ts +85 -0
  69. package/src/utils.ts +53 -0
  70. package/stacks/cloudflare/skills/cloudflare-d1-kv/SKILL.md +84 -0
  71. package/stacks/cloudflare/stack.json +26 -0
  72. package/stacks/i18n-typesafe/skills/i18n-typesafe/SKILL.md +64 -0
  73. package/stacks/i18n-typesafe/stack.json +25 -0
  74. package/stacks/protobuf/skills/protobuf-contracts/SKILL.md +78 -0
  75. package/stacks/protobuf/stack.json +25 -0
  76. package/stacks/rust-wasm/skills/rust-wasm-patterns/SKILL.md +76 -0
  77. package/stacks/rust-wasm/stack.json +26 -0
  78. package/stacks/solidjs/skills/solidjs-patterns/SKILL.md +66 -0
  79. package/stacks/solidjs/stack.json +52 -0
  80. package/stacks/vanilla-extract/skills/vanilla-extract-patterns/SKILL.md +76 -0
  81. package/stacks/vanilla-extract/stack.json +40 -0
  82. package/templates/claude-toolkit.config.ts +34 -0
  83. package/templates/configs/biome.base.json +35 -0
  84. package/templates/configs/tsconfig.base.json +16 -0
  85. package/templates/skill-rules.base.json +98 -0
@@ -0,0 +1,119 @@
1
+ # Essential Patterns
2
+
3
+ > Source: [Four Essential TypeScript Patterns You Can't Work Without](https://www.totaltypescript.com/four-essential-typescript-patterns) — Matt Pocock
4
+
5
+ ## 1. Branded Types
6
+
7
+ Create **validation boundaries** by tagging base types with a unique label. Prevents mixing validated and unvalidated values of the same underlying type.
8
+
9
+ ```typescript
10
+ type Brand<T, TBrand extends string> = T & { __brand: TBrand };
11
+
12
+ type Password = Brand<string, "Password">;
13
+ type Email = Brand<string, "Email">;
14
+
15
+ function validatePassword(input: string): Password {
16
+ if (input.length < 8) throw new Error("Too short");
17
+ return input as Password;
18
+ }
19
+
20
+ function login(email: Email, password: Password) {
21
+ // Both values are guaranteed to have been validated
22
+ }
23
+
24
+ // login("user@test.com", "short") — Error! Raw strings are not Password/Email
25
+ ```
26
+
27
+ **When to use:** Anywhere you need to ensure a value has passed through validation — passwords, emails, sanitized HTML, monetary amounts, database IDs.
28
+
29
+ ## 2. Globals
30
+
31
+ Understand and manage TypeScript's **global type scope** for typing JavaScript globals like `process.env`, `window`, or custom global functions.
32
+
33
+ ```typescript
34
+ declare global {
35
+ function myGlobalFunc(): boolean;
36
+ var myGlobalVar: number;
37
+ }
38
+
39
+ // Now available everywhere without imports
40
+ console.log(myGlobalVar);
41
+ myGlobalFunc();
42
+ ```
43
+
44
+ **Practical use — strongly typing `process.env`:**
45
+
46
+ ```typescript
47
+ declare global {
48
+ namespace NodeJS {
49
+ interface ProcessEnv {
50
+ DATABASE_URL: string;
51
+ API_KEY: string;
52
+ NODE_ENV: "development" | "production" | "test";
53
+ }
54
+ }
55
+ }
56
+
57
+ // process.env.DATABASE_URL is now typed as string (not string | undefined)
58
+ ```
59
+
60
+ ## 3. Assertion Functions & Type Predicates
61
+
62
+ Both patterns improve TypeScript's ability to narrow types.
63
+
64
+ ### Type Predicates
65
+
66
+ Narrow types within conditionals using `is`:
67
+
68
+ ```typescript
69
+ const values = ["a", "b", undefined, "c", undefined];
70
+
71
+ const filtered = values.filter((v): v is string => Boolean(v));
72
+ // string[] — TypeScript knows undefined was removed
73
+ ```
74
+
75
+ ### Assertion Functions
76
+
77
+ Enforce type guarantees or throw errors using `asserts`:
78
+
79
+ ```typescript
80
+ function assertIsString(value: unknown): asserts value is string {
81
+ if (typeof value !== "string") {
82
+ throw new Error(`Expected string, got ${typeof value}`);
83
+ }
84
+ }
85
+
86
+ function process(input: unknown) {
87
+ assertIsString(input);
88
+ // input is narrowed to string from here on
89
+ console.log(input.toUpperCase());
90
+ }
91
+ ```
92
+
93
+ **Key difference:** Predicates return `boolean` and work in `if`/`filter`. Assertions return `void` and narrow the type for all subsequent code in the scope.
94
+
95
+ ## 4. Classes (for Library APIs)
96
+
97
+ Classes enable the **builder pattern** and self-typing structures — particularly useful in library code.
98
+
99
+ ```typescript
100
+ class SDK {
101
+ loggedInUser?: User;
102
+
103
+ constructor(loggedInUser?: User) {
104
+ this.loggedInUser = loggedInUser;
105
+ }
106
+
107
+ assertIsLoggedIn(): asserts this is this & { loggedInUser: User } {
108
+ if (!this.loggedInUser) {
109
+ throw new Error("Not logged in");
110
+ }
111
+ }
112
+ }
113
+
114
+ const sdk = new SDK();
115
+ sdk.assertIsLoggedIn();
116
+ // sdk.loggedInUser is now User (not User | undefined)
117
+ ```
118
+
119
+ **When to use:** Libraries and SDKs where you need fluent APIs, chainable methods, or internal type refinement. This pattern powers libraries like tRPC.
@@ -0,0 +1,105 @@
1
+ # Generics Patterns
2
+
3
+ > Sources: [TypeScript Generics in 3 Easy Patterns](https://www.totaltypescript.com/typescript-generics-in-three-easy-patterns), [There Is No Such Thing As A Generic](https://www.totaltypescript.com/no-such-thing-as-a-generic) — Matt Pocock
4
+
5
+ ## Mental Model
6
+
7
+ Matt argues that "generics" is a misleading name. What people call generics is actually **three distinct patterns** for passing type arguments around.
8
+
9
+ ## Pattern 1: Passing Types to Types
10
+
11
+ Create reusable type definitions that accept type parameters — like function arguments, but for types.
12
+
13
+ ```typescript
14
+ type ApiResponse<TData> = {
15
+ data: TData;
16
+ error?: { message: string };
17
+ };
18
+
19
+ type UserResponse = ApiResponse<{
20
+ id: string;
21
+ name: string;
22
+ }>;
23
+
24
+ type OrderResponse = ApiResponse<{
25
+ orderId: string;
26
+ total: number;
27
+ }>;
28
+ ```
29
+
30
+ This eliminates repetitive wrapper types while keeping each response strongly typed.
31
+
32
+ ## Pattern 2: Passing Types to Functions
33
+
34
+ Explicitly specify type arguments when calling a function:
35
+
36
+ ```typescript
37
+ const createSet = <T>() => {
38
+ return new Set<T>();
39
+ };
40
+
41
+ const stringSet = createSet<string>();
42
+ const numberSet = createSet<number>();
43
+ ```
44
+
45
+ Use this when TypeScript has no value to infer from — the function takes no arguments of type `T`.
46
+
47
+ ## Pattern 3: Inferring Types from Arguments
48
+
49
+ The most common and powerful pattern. TypeScript deduces type parameters from the values you pass:
50
+
51
+ ```typescript
52
+ const createSet = <T>(initial: T) => {
53
+ return new Set<T>([initial]);
54
+ };
55
+
56
+ const stringSet = createSet("matt"); // Set<string>
57
+ const numberSet = createSet(123); // Set<number>
58
+ ```
59
+
60
+ A practical example with constraints:
61
+
62
+ ```typescript
63
+ const objKeys = <T extends object>(obj: T): Array<keyof T> => {
64
+ return Object.keys(obj) as Array<keyof T>;
65
+ };
66
+
67
+ const keys = objKeys({ a: 1, b: 2 });
68
+ // ("a" | "b")[]
69
+ ```
70
+
71
+ The `extends object` constraint ensures only objects are accepted, while `keyof T` preserves the specific key types.
72
+
73
+ ## When to Use Generics vs Unions
74
+
75
+ From Matt's tip "Know when to use generics":
76
+
77
+ **Use generics** when the output type depends on the input type — the caller's choice flows through the function.
78
+
79
+ ```typescript
80
+ // Generic: return type depends on input
81
+ function first<T>(arr: T[]): T | undefined {
82
+ return arr[0];
83
+ }
84
+ ```
85
+
86
+ **Use unions** when the function handles a fixed set of types internally.
87
+
88
+ ```typescript
89
+ // Union: function handles all cases itself
90
+ function format(value: string | number): string {
91
+ return String(value);
92
+ }
93
+ ```
94
+
95
+ ## Constraining Generics
96
+
97
+ Use `extends` to document expectations and catch misuse at the call site:
98
+
99
+ ```typescript
100
+ function merge<T extends object, U extends object>(a: T, b: U): T & U {
101
+ return { ...a, ...b };
102
+ }
103
+ ```
104
+
105
+ Without the constraint, callers could pass primitives and get confusing errors deep inside the implementation.
@@ -0,0 +1,87 @@
1
+ # Micro-Opinions
2
+
3
+ > Small but specific stances from Matt Pocock on everyday TypeScript choices.
4
+
5
+ ## Declare Return Types for Top-Level Functions
6
+
7
+ > Source: [Should You Declare Return Types?](https://www.totaltypescript.com/should-you-declare-return-types)
8
+
9
+ Declare return types on module-level functions. This communicates intent and helps both humans and AI tools understand what a function is designed to return.
10
+
11
+ ```typescript
12
+ // Do this for top-level functions
13
+ const fetchUser = async (id: string): Promise<User> => {
14
+ const res = await fetch(`/api/users/${id}`);
15
+ return res.json();
16
+ };
17
+ ```
18
+
19
+ **Exception:** Skip return types for components returning JSX — the return type is always obvious.
20
+
21
+ ```typescript
22
+ // Skip for JSX-returning components
23
+ const Avatar = (props: AvatarProps) => {
24
+ return <img alt={props.name} />;
25
+ };
26
+ ```
27
+
28
+ ## Prefer `const` Over `let`
29
+
30
+ > Source: [How let and const Work In TypeScript](https://www.totaltypescript.com/let-and-const)
31
+
32
+ `const` gives TypeScript narrower, literal type inference. `let` widens to the base type because the variable could be reassigned.
33
+
34
+ ```typescript
35
+ const genre = "rock"; // type: "rock" (literal)
36
+ let genre = "rock"; // type: string (widened)
37
+ ```
38
+
39
+ Prefer `const` to get stricter types. If you must use `let`, add an explicit type annotation.
40
+
41
+ ## Prefer `T[]` Over `Array<T>`
42
+
43
+ > Source: [Array\<T\> vs T[]: Which is better?](https://www.totaltypescript.com/array-types-in-typescript)
44
+
45
+ Both are functionally identical. Matt prefers `T[]` because:
46
+ - TypeScript's compiler, hover info, and error messages always use `T[]` syntax
47
+ - It feels more natural and is used throughout the official docs
48
+
49
+ **Caveat:** `Array<keyof Person>` avoids the need for parentheses that `(keyof Person)[]` requires. Minor edge case.
50
+
51
+ **What matters most:** Pick one and enforce it with an ESLint rule. Consistency beats preference.
52
+
53
+ ## Don't Use Method Shorthand Syntax
54
+
55
+ > Source: [Method Shorthand Syntax Considered Harmful](https://www.totaltypescript.com/method-shorthand-syntax-considered-harmful)
56
+
57
+ Method shorthand in interfaces/types is **bivariant** — it accepts parameter types both narrower and wider than specified, creating a type safety gap.
58
+
59
+ ```typescript
60
+ // Bivariant (unsafe) — allows narrowing the parameter
61
+ interface Handler {
62
+ handle(input: Animal): void;
63
+ }
64
+
65
+ // Properly covariant (safe)
66
+ interface Handler {
67
+ handle: (input: Animal) => void;
68
+ }
69
+ ```
70
+
71
+ With the shorthand, you can implement `handle` expecting `Dog` instead of `Animal`, then pass a `Cat` at runtime — TypeScript won't catch it.
72
+
73
+ **Enforcement:** Use the ESLint rule `@typescript-eslint/method-signature-style` with `"property"` option.
74
+
75
+ ## Never Use the `Function` Type
76
+
77
+ > Source: [Don't use Function type in TypeScript](https://www.totaltypescript.com/dont-use-function-keyword-in-typescript)
78
+
79
+ `Function` represents *any* function with no type information. It kills inference, autocomplete, and safety.
80
+
81
+ | Instead of | Use |
82
+ |---|---|
83
+ | `Function` | `(...args: any[]) => any` (any function) |
84
+ | `Function` | `() => void` (no-arg callback) |
85
+ | `Function` | `(item: T) => number` (specific signature) |
86
+
87
+ Be as specific as possible. The more precise the function type, the more TypeScript can help you.
@@ -0,0 +1,62 @@
1
+ # Runtime Validation
2
+
3
+ > Source: [When Should You Use Zod?](https://www.totaltypescript.com/when-should-you-use-zod) — Matt Pocock
4
+
5
+ ## The Framework: Trust Boundaries
6
+
7
+ Matt's recommendation is based on how much you trust the data entering your application.
8
+
9
+ ## Use Zod: Untrusted Inputs
10
+
11
+ Validate data you don't control. These are attack vectors and sources of runtime surprises:
12
+
13
+ - **CLI arguments** (`process.argv`)
14
+ - **Public API endpoints** (path params, headers, request bodies)
15
+ - **Form submissions**
16
+ - **WebSocket connections**
17
+ - **`localStorage`** (users can manipulate it directly)
18
+
19
+ ```typescript
20
+ import { z } from "zod";
21
+
22
+ const CreateUserSchema = z.object({
23
+ name: z.string().min(1),
24
+ email: z.string().email(),
25
+ age: z.number().int().positive(),
26
+ });
27
+
28
+ // At the API boundary
29
+ const result = CreateUserSchema.safeParse(req.body);
30
+ if (!result.success) {
31
+ return res.status(400).json(result.error);
32
+ }
33
+ // result.data is now fully typed and validated
34
+ ```
35
+
36
+ As Matt notes: "If these APIs are exposed to the world, anyone can ping them. If they aren't validated, many might even be vectors for attack."
37
+
38
+ ## Consider Zod: Third-Party APIs
39
+
40
+ APIs you don't control can change without warning. Validation at the boundary catches drift early:
41
+
42
+ > "Validation will be thrown early, right when the data enters your app. This makes it much easier to debug and fix."
43
+
44
+ **Tradeoff:** Zod adds ~12kb gzipped. Consider whether that matters for your bundle.
45
+
46
+ ## Skip Zod: Controlled Inputs
47
+
48
+ When you control both ends of the data flow (e.g., fullstack app where your frontend talks to your own backend):
49
+
50
+ - Version drift is "usually just a browser refresh away from a better experience"
51
+ - The security risk is minimal since you control the server
52
+ - The overhead of maintaining schemas for internal data isn't worth it
53
+
54
+ ## Summary
55
+
56
+ | Data Source | Trust Level | Validate? |
57
+ |---|---|---|
58
+ | User input (forms, CLI, localStorage) | None | Yes |
59
+ | Public API endpoints | None | Yes |
60
+ | Third-party APIs | Low | Recommended |
61
+ | Your own backend (same deploy) | High | Usually skip |
62
+ | Internal function calls | Full | Never |
@@ -0,0 +1,100 @@
1
+ # The `satisfies` Operator
2
+
3
+ > Source: [5 Ways to Use Satisfies in TypeScript](https://www.totaltypescript.com/how-to-use-satisfies-operator) — Matt Pocock
4
+
5
+ ## What It Does
6
+
7
+ `satisfies` validates that a value conforms to a type **without widening the inferred type**. You get compile-time validation and narrow inference at the same time.
8
+
9
+ ## 5 Practical Uses
10
+
11
+ ### 1. Strongly Typed URL Search Parameters
12
+
13
+ `URLSearchParams` normally accepts loose `Record<string, string>`. Use `satisfies` to catch missing required fields:
14
+
15
+ ```typescript
16
+ type GHIssueURLParams = {
17
+ title: string;
18
+ body: string;
19
+ };
20
+
21
+ const params = new URLSearchParams({
22
+ title: "New Issue",
23
+ } satisfies GHIssueURLParams);
24
+ // Error: Property 'body' is missing
25
+ ```
26
+
27
+ ### 2. Strongly Typed POST Request Bodies
28
+
29
+ `JSON.stringify` erases type information. Validate the body shape before serialization:
30
+
31
+ ```typescript
32
+ type Post = {
33
+ title: string;
34
+ content: string;
35
+ };
36
+
37
+ fetch("/api/posts", {
38
+ method: "POST",
39
+ body: JSON.stringify({
40
+ title: "New Post",
41
+ content: "Lorem ipsum.",
42
+ } satisfies Post),
43
+ });
44
+ ```
45
+
46
+ ### 3. Inferring Tuples Without `as const`
47
+
48
+ Get tuple behavior with index bounds checking:
49
+
50
+ ```typescript
51
+ type MoreThanOneMember = [any, ...any[]];
52
+
53
+ const tuple = [1, 2, 3] satisfies MoreThanOneMember;
54
+ const doesNotExist = tuple[3]; // Error: index out of bounds
55
+ ```
56
+
57
+ ### 4. Enforcing `as const` Object Shapes
58
+
59
+ Combine `as const` with `satisfies` to get immutable objects that must conform to a shape:
60
+
61
+ ```typescript
62
+ type RouteConfig = Record<
63
+ string,
64
+ { url: string; searchParams: Record<string, string> }
65
+ >;
66
+
67
+ const routes = {
68
+ home: { url: "/", searchParams: {} },
69
+ about: { url: "/about", searchParams: {} },
70
+ } as const satisfies RouteConfig;
71
+
72
+ // routes.home.url is narrowed to "/" (not string)
73
+ // AND the shape is validated against RouteConfig
74
+ ```
75
+
76
+ ### 5. Enforcing `as const` Array Shapes
77
+
78
+ Validate recursive structures while preserving literal types:
79
+
80
+ ```typescript
81
+ type NavElement = {
82
+ title: string;
83
+ url?: string;
84
+ children?: readonly NavElement[];
85
+ };
86
+
87
+ const nav = [
88
+ { title: "Home", url: "/" },
89
+ {
90
+ title: "About",
91
+ children: [{ title: "Team", url: "/about/team" }],
92
+ },
93
+ ] as const satisfies readonly NavElement[];
94
+ ```
95
+
96
+ **Important:** Array properties in the type must be marked `readonly` to align with `as const`'s immutability.
97
+
98
+ ## When to Reach for `satisfies`
99
+
100
+ Use it when you need **both** validation against a type **and** narrow inference of the actual value. If you only need one or the other, a regular type annotation or `as const` alone is sufficient.
@@ -0,0 +1,129 @@
1
+ # TSConfig Cheat Sheet
2
+
3
+ > Source: [The TSConfig Cheat Sheet](https://www.totaltypescript.com/tsconfig-cheat-sheet) — Matt Pocock
4
+
5
+ ## Base Options (Every Project)
6
+
7
+ These belong in every `tsconfig.json`:
8
+
9
+ ```jsonc
10
+ {
11
+ "compilerOptions": {
12
+ // Smooth over CJS/ESM interop differences
13
+ "esModuleInterop": true,
14
+
15
+ // Skip type-checking node_modules .d.ts files for performance
16
+ "skipLibCheck": true,
17
+
18
+ // Stable target — prefer over "esnext"
19
+ "target": "es2022",
20
+
21
+ // Allow importing .js and .json files
22
+ "allowJs": true,
23
+ "resolveJsonModule": true,
24
+
25
+ // Treat all files as modules (avoids redeclaration errors)
26
+ "moduleDetection": "force",
27
+
28
+ // Prevent unsafe TS features that break per-file transpilation
29
+ "isolatedModules": true,
30
+
31
+ // Enforce import type / export type syntax
32
+ "verbatimModuleSyntax": true
33
+ }
34
+ }
35
+ ```
36
+
37
+ ## Strictness
38
+
39
+ Enable all strict checks, plus two extras Matt considers essential:
40
+
41
+ ```jsonc
42
+ {
43
+ "compilerOptions": {
44
+ // All strict type-checking options
45
+ "strict": true,
46
+
47
+ // Force checking array/object index access (prevents undefined bugs)
48
+ "noUncheckedIndexedAccess": true,
49
+
50
+ // Make the override keyword functional in classes
51
+ "noImplicitOverride": true
52
+ }
53
+ }
54
+ ```
55
+
56
+ Matt **deliberately excludes** noisier options like `noImplicitReturns`, `noUnusedLocals`, and `noUnusedParameters`. Add them only if your team wants them — they create friction during development.
57
+
58
+ ## When TypeScript Transpiles (tsc emits JS)
59
+
60
+ ```jsonc
61
+ {
62
+ "compilerOptions": {
63
+ "module": "NodeNext",
64
+ "outDir": "dist"
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### For Published Libraries
70
+
71
+ Add `.d.ts` generation so consumers get autocomplete:
72
+
73
+ ```jsonc
74
+ {
75
+ "compilerOptions": {
76
+ "declaration": true
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### For Monorepo Packages
82
+
83
+ ```jsonc
84
+ {
85
+ "compilerOptions": {
86
+ "composite": true,
87
+ "sourceMap": true,
88
+ "declarationMap": true
89
+ }
90
+ }
91
+ ```
92
+
93
+ ## When TypeScript Does NOT Transpile (Linting Mode)
94
+
95
+ When a bundler (Vite, esbuild, etc.) handles transpilation:
96
+
97
+ ```jsonc
98
+ {
99
+ "compilerOptions": {
100
+ // Mimic bundler module resolution
101
+ "module": "preserve",
102
+
103
+ // Don't emit JS files
104
+ "noEmit": true
105
+ }
106
+ }
107
+ ```
108
+
109
+ ## Environment-Specific `lib`
110
+
111
+ **DOM environments** (browsers, SSR with DOM APIs):
112
+
113
+ ```jsonc
114
+ {
115
+ "compilerOptions": {
116
+ "lib": ["es2022", "dom", "dom.iterable"]
117
+ }
118
+ }
119
+ ```
120
+
121
+ **Non-DOM environments** (Node.js CLIs, serverless, workers):
122
+
123
+ ```jsonc
124
+ {
125
+ "compilerOptions": {
126
+ "lib": ["es2022"]
127
+ }
128
+ }
129
+ ```
@@ -0,0 +1,64 @@
1
+ # Type Organization
2
+
3
+ > Source: [Where To Put Your Types in Application Code](https://www.totaltypescript.com/where-to-put-your-types-in-application-code) — Matt Pocock
4
+
5
+ ## Three Rules
6
+
7
+ ### Rule 1: Colocate Single-Use Types
8
+
9
+ When a type is used in only one place, put it in the same file where it's used.
10
+
11
+ ```typescript
12
+ // components/Avatar.tsx
13
+ type AvatarProps = {
14
+ imageUrl: string;
15
+ name: string;
16
+ };
17
+
18
+ export function Avatar({ imageUrl, name }: AvatarProps) {
19
+ // ...
20
+ }
21
+ ```
22
+
23
+ Don't extract single-use types into separate files. It's low-cost to refactor later if the type grows in scope. Inlining is fine for truly single-use types.
24
+
25
+ ### Rule 2: Share Types Across Modules
26
+
27
+ When a type serves multiple files, move it to a shared `*.types.ts` file at the appropriate level:
28
+
29
+ - **App-wide types** → `src/types.ts` or `src/shared.types.ts`
30
+ - **Folder-specific types** → `src/features/auth/auth.types.ts`
31
+
32
+ This mirrors how you'd handle shared functions — keep them at the narrowest scope that covers all consumers.
33
+
34
+ ```
35
+ src/
36
+ ├── types.ts # App-wide types
37
+ ├── features/
38
+ │ ├── auth/
39
+ │ │ ├── auth.types.ts # Shared within auth feature
40
+ │ │ ├── login.tsx
41
+ │ │ └── signup.tsx
42
+ │ └── billing/
43
+ │ ├── billing.types.ts
44
+ │ └── invoice.tsx
45
+ ```
46
+
47
+ ### Rule 3: Monorepo-Level Sharing
48
+
49
+ In a monorepo, types used across multiple packages go in a dedicated shared package:
50
+
51
+ ```
52
+ packages/
53
+ ├── types/ # Shared types package
54
+ │ └── src/
55
+ │ └── index.ts
56
+ ├── web-app/
57
+ │ └── src/
58
+ └── api/
59
+ └── src/
60
+ ```
61
+
62
+ ## Core Principle
63
+
64
+ Share types across the **smallest number of modules** that require them. Don't pre-extract types "just in case" — colocate by default and widen scope only when a second consumer appears.