ghcopilot-hub 1.0.0
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.
- package/README.md +176 -0
- package/hub/agents/README.md +243 -0
- package/hub/agents/archiver.agent.md +231 -0
- package/hub/agents/explore.agent.md +49 -0
- package/hub/agents/implementador.agent.md +176 -0
- package/hub/agents/librarian.agent.md +34 -0
- package/hub/agents/momus.agent.md +130 -0
- package/hub/agents/oracle.agent.md +52 -0
- package/hub/agents/plan-guardian.agent.md +109 -0
- package/hub/agents/planificador.agent.md +295 -0
- package/hub/agents/test-sentinel.agent.md +106 -0
- package/hub/base/.github/copilot-instructions.md +10 -0
- package/hub/base/.github/instructions/ghcopilot-hub.instructions.md +6 -0
- package/hub/base/.github/prompts/ghcopilot-hub-maintenance.prompt.md +8 -0
- package/hub/base/.vscode/settings.json +1 -0
- package/hub/packs/base-web.json +4 -0
- package/hub/packs/nextjs-ssr.json +4 -0
- package/hub/packs/node-api.json +4 -0
- package/hub/packs/spa-tanstack.json +4 -0
- package/hub/skills/architecture-testing/SKILL.md +108 -0
- package/hub/skills/architecture-testing/references/archunitts.md +46 -0
- package/hub/skills/ghcopilot-hub-consumer/SKILL.md +115 -0
- package/hub/skills/ghcopilot-hub-consumer/references/workflow.md +39 -0
- package/hub/skills/mermaid-expert/SKILL.md +152 -0
- package/hub/skills/mermaid-expert/assets/examples/c4_model.md +121 -0
- package/hub/skills/mermaid-expert/assets/examples/flowchart.md +123 -0
- package/hub/skills/mermaid-expert/assets/examples/img/base_minimal.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/corporate.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/dark.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/dark_neo.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/default_neo.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/forest_corp.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/handdrawn.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/neo.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/neutral_sketch.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/img/retro.png +0 -0
- package/hub/skills/mermaid-expert/assets/examples/sequence.md +116 -0
- package/hub/skills/mermaid-expert/assets/examples/styles_and_looks.md +102 -0
- package/hub/skills/mermaid-expert/assets/examples/technical.md +130 -0
- package/hub/skills/mermaid-expert/assets/examples.md +57 -0
- package/hub/skills/mermaid-expert/references/cheatsheet.md +88 -0
- package/hub/skills/mermaid-expert/references/validation.md +66 -0
- package/hub/skills/react/SKILL.md +235 -0
- package/hub/skills/react/references/common-mistakes.md +518 -0
- package/hub/skills/react/references/composition-patterns.md +526 -0
- package/hub/skills/react/references/effects-patterns.md +396 -0
- package/hub/skills/react/references/react-compiler.md +268 -0
- package/hub/skills/react-hook-form/SKILL.md +291 -0
- package/hub/skills/react-hook-form/references/field-arrays.md +98 -0
- package/hub/skills/react-hook-form/references/integration.md +102 -0
- package/hub/skills/react-hook-form/references/performance.md +96 -0
- package/hub/skills/skill-creator/SKILL.md +152 -0
- package/hub/skills/skill-creator/assets/SKILL-TEMPLATE.md +84 -0
- package/hub/skills/skill-judge/README.md +261 -0
- package/hub/skills/skill-judge/SKILL.md +806 -0
- package/hub/skills/tailwind/SKILL.md +200 -0
- package/hub/skills/tanstack/SKILL.md +284 -0
- package/hub/skills/tanstack/references/loader-adapter-examples.md +79 -0
- package/hub/skills/tanstack/references/query-options-examples.md +115 -0
- package/hub/skills/tanstack/references/resilience-patterns.md +110 -0
- package/hub/skills/tanstack/references/suspense-consumption-examples.md +82 -0
- package/hub/skills/tanstack-query/SKILL.md +241 -0
- package/hub/skills/tanstack-query/references/advanced-hooks.md +126 -0
- package/hub/skills/tanstack-query/references/best-practices.md +241 -0
- package/hub/skills/tanstack-query/references/cache-strategies.md +474 -0
- package/hub/skills/tanstack-query/references/common-patterns.md +239 -0
- package/hub/skills/tanstack-query/references/migration-v5.md +93 -0
- package/hub/skills/tanstack-query/references/resilience-and-mutations.md +63 -0
- package/hub/skills/tanstack-query/references/testing.md +116 -0
- package/hub/skills/tanstack-query/references/top-errors.md +148 -0
- package/hub/skills/tanstack-query/references/typescript.md +176 -0
- package/hub/skills/tanstack-router/SKILL.md +145 -0
- package/hub/skills/tanstack-router/references/code-splitting.md +31 -0
- package/hub/skills/tanstack-router/references/errors-and-boundaries.md +44 -0
- package/hub/skills/tanstack-router/references/loaders-and-preload.md +51 -0
- package/hub/skills/tanstack-router/references/navigation.md +24 -0
- package/hub/skills/tanstack-router/references/private-routes.md +169 -0
- package/hub/skills/tanstack-router/references/router-context.md +35 -0
- package/hub/skills/tanstack-router/references/search-params.md +29 -0
- package/hub/skills/tanstack-router/references/typescript.md +24 -0
- package/hub/skills/testing/SKILL.md +187 -0
- package/hub/skills/testing/references/assertions.md +64 -0
- package/hub/skills/testing/references/async-testing.md +66 -0
- package/hub/skills/testing/references/e2e-strategy.md +69 -0
- package/hub/skills/testing/references/layer-matrix.md +67 -0
- package/hub/skills/testing/references/performance.md +49 -0
- package/hub/skills/testing/references/tooling-map.md +81 -0
- package/hub/skills/testing/references/zustand-mocking.md +84 -0
- package/hub/skills/typescript/SKILL.md +232 -0
- package/hub/skills/typescript/references/perf-additional-concerns.md +248 -0
- package/hub/skills/typescript/references/perf-execution-cache-locality.md +178 -0
- package/hub/skills/typescript/references/reduce-branching.md +147 -0
- package/hub/skills/typescript/references/reduce-looping.md +203 -0
- package/hub/skills/typescript/references/style-and-types.md +171 -0
- package/hub/skills/typescript/references/type-vs-interface.md +27 -0
- package/hub/skills/zod/SKILL.md +219 -0
- package/hub/skills/zustand/SKILL.md +273 -0
- package/package.json +59 -0
- package/tooling/cli/src/bin.js +11 -0
- package/tooling/cli/src/cli.js +409 -0
- package/tooling/cli/src/lib/catalog-loader.js +191 -0
- package/tooling/cli/src/lib/constants.js +39 -0
- package/tooling/cli/src/lib/errors.js +8 -0
- package/tooling/cli/src/lib/frontmatter.js +41 -0
- package/tooling/cli/src/lib/fs-utils.js +77 -0
- package/tooling/cli/src/lib/managed-header.js +74 -0
- package/tooling/cli/src/lib/manifest.js +105 -0
- package/tooling/cli/src/lib/resolver.js +53 -0
- package/tooling/cli/src/lib/sync-engine.js +262 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Predictable Execution and Cache Locality
|
|
2
|
+
|
|
3
|
+
## Load Scope & Quick Navigation
|
|
4
|
+
|
|
5
|
+
Load this file for data-layout and access-pattern optimization (sequential access, struct-of-arrays, branch predictability).
|
|
6
|
+
|
|
7
|
+
Do NOT load this file for basic TS syntax, naming conventions, or type-system-only concerns.
|
|
8
|
+
|
|
9
|
+
Quick navigation:
|
|
10
|
+
|
|
11
|
+
- Access pattern choice → [Sequential vs Random Access](#sequential-vs-random-access)
|
|
12
|
+
- Data layout choice → [Struct-of-Arrays vs Array-of-Structs](#struct-of-arrays-vs-array-of-structs)
|
|
13
|
+
|
|
14
|
+
## Issues
|
|
15
|
+
|
|
16
|
+
- Poor data structure layout for access pattern
|
|
17
|
+
- Random access patterns that could be sequential
|
|
18
|
+
- Struct-of-arrays vs array-of-structs mismatches
|
|
19
|
+
- Scattered memory access in tight loops
|
|
20
|
+
- Unpredictable control flow
|
|
21
|
+
|
|
22
|
+
## Optimizations
|
|
23
|
+
|
|
24
|
+
- Sequential memory access patterns
|
|
25
|
+
- Group related data together
|
|
26
|
+
- Use flat arrays instead of nested structures
|
|
27
|
+
- Consider columnar layout for analytics workloads
|
|
28
|
+
- Write code with clear, predictable execution paths
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
### Sequential vs Random Access
|
|
33
|
+
|
|
34
|
+
**❌ Incorrect: random access pattern**
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const users = new Map();
|
|
38
|
+
users.set("id1", { name: "Alice", age: 30 });
|
|
39
|
+
users.set("id2", { name: "Bob", age: 25 });
|
|
40
|
+
|
|
41
|
+
// Random access through Map
|
|
42
|
+
for (const id of shuffledIds) {
|
|
43
|
+
process(users.get(id));
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**✅ Correct: sequential access**
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const users = [
|
|
51
|
+
{ id: "id1", name: "Alice", age: 30 },
|
|
52
|
+
{ id: "id2", name: "Bob", age: 25 },
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
// Sequential memory access
|
|
56
|
+
for (let i = 0; i < users.length; i++) {
|
|
57
|
+
process(users[i]);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Struct-of-Arrays vs Array-of-Structs
|
|
62
|
+
|
|
63
|
+
**❌ Incorrect: array-of-structs for columnar access**
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const particles = [
|
|
67
|
+
{ x: 1, y: 2, vx: 0.1, vy: 0.2 },
|
|
68
|
+
{ x: 3, y: 4, vx: 0.3, vy: 0.4 },
|
|
69
|
+
// ... thousands more
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
// Need only x coordinates - poor cache usage
|
|
73
|
+
for (let i = 0; i < particles.length; i++) {
|
|
74
|
+
updateX(particles[i].x);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**✅ Correct: struct-of-arrays for columnar workload**
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const particles = {
|
|
82
|
+
x: [1, 3 /* ... */],
|
|
83
|
+
y: [2, 4 /* ... */],
|
|
84
|
+
vx: [0.1, 0.3 /* ... */],
|
|
85
|
+
vy: [0.2, 0.4 /* ... */],
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Sequential access to contiguous memory
|
|
89
|
+
for (let i = 0; i < particles.x.length; i++) {
|
|
90
|
+
updateX(particles.x[i]);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Flat Arrays vs Nested Structures
|
|
95
|
+
|
|
96
|
+
**❌ Incorrect: nested object access**
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const grid = {
|
|
100
|
+
rows: [{ cells: [{ value: 1 }, { value: 2 }] }, { cells: [{ value: 3 }, { value: 4 }] }],
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
for (const row of grid.rows) {
|
|
104
|
+
for (const cell of row.cells) {
|
|
105
|
+
process(cell.value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**✅ Correct: flat array**
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const values = [1, 2, 3, 4];
|
|
114
|
+
const width = 2;
|
|
115
|
+
|
|
116
|
+
for (let i = 0; i < values.length; i++) {
|
|
117
|
+
process(values[i]);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Group Related Data
|
|
122
|
+
|
|
123
|
+
**❌ Incorrect: scattered data access**
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
const ids = [1, 2, 3];
|
|
127
|
+
const names = ["Alice", "Bob", "Charlie"];
|
|
128
|
+
const ages = [30, 25, 35];
|
|
129
|
+
|
|
130
|
+
for (let i = 0; i < ids.length; i++) {
|
|
131
|
+
processUser(ids[i], names[i], ages[i]);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**✅ Correct: grouped data**
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
const users = [
|
|
139
|
+
{ id: 1, name: "Alice", age: 30 },
|
|
140
|
+
{ id: 2, name: "Bob", age: 25 },
|
|
141
|
+
{ id: 3, name: "Charlie", age: 35 },
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
for (let i = 0; i < users.length; i++) {
|
|
145
|
+
const user = users[i];
|
|
146
|
+
processUser(user.id, user.name, user.age);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Predictable Control Flow
|
|
151
|
+
|
|
152
|
+
**❌ Incorrect: unpredictable branches**
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
function process(items) {
|
|
156
|
+
for (const item of items) {
|
|
157
|
+
if (Math.random() > 0.5) {
|
|
158
|
+
handleA(item);
|
|
159
|
+
} else {
|
|
160
|
+
handleB(item);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**✅ Correct: predictable branches**
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
function process(items) {
|
|
170
|
+
for (const item of items) {
|
|
171
|
+
if (item.type === "A") {
|
|
172
|
+
handleA(item);
|
|
173
|
+
} else {
|
|
174
|
+
handleB(item);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Reduce Branching
|
|
2
|
+
|
|
3
|
+
## Load Scope & Quick Navigation
|
|
4
|
+
|
|
5
|
+
Load this file when conditionals/switches are deeply nested or repeated and control flow dominates complexity.
|
|
6
|
+
|
|
7
|
+
Do NOT load this file when the primary issue is array pass count or cache-locality/data-layout concerns.
|
|
8
|
+
|
|
9
|
+
Quick navigation:
|
|
10
|
+
|
|
11
|
+
- Replace conditional chains → [Switch to Lookup Table](#switch-to-lookup-table)
|
|
12
|
+
- Flatten deep nesting → [Nested Conditionals to Early Returns](#nested-conditionals-to-early-returns)
|
|
13
|
+
|
|
14
|
+
## Issues
|
|
15
|
+
|
|
16
|
+
- Excessive nested conditionals (>3 levels)
|
|
17
|
+
- Switch statements that could be lookup tables
|
|
18
|
+
- Repeated condition checks in same scope
|
|
19
|
+
- Polymorphic branching on hot paths
|
|
20
|
+
- Type guards that could be avoided
|
|
21
|
+
|
|
22
|
+
## Optimizations
|
|
23
|
+
|
|
24
|
+
- Convert switch/if-chains to object/Map lookups
|
|
25
|
+
- Hoist invariant conditions
|
|
26
|
+
- Use early returns to reduce nesting
|
|
27
|
+
- Replace runtime type checks with compile-time guarantees
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### Switch to Lookup Table
|
|
32
|
+
|
|
33
|
+
**❌ Incorrect: conditional checks**
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
if (thing === "ONE") {
|
|
37
|
+
/*...*/
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (thing === "TWO") {
|
|
41
|
+
/*...*/
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (thing === "THREE") {
|
|
45
|
+
/*...*/
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**✅ Correct: lookup table**
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const lookup = {
|
|
53
|
+
ONE: {
|
|
54
|
+
/*...*/
|
|
55
|
+
},
|
|
56
|
+
TWO: {
|
|
57
|
+
/*...*/
|
|
58
|
+
},
|
|
59
|
+
THREE: {
|
|
60
|
+
/*...*/
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const action = lookup[thing];
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Nested Conditionals to Early Returns
|
|
68
|
+
|
|
69
|
+
**❌ Incorrect: excessive nesting**
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
function process(data) {
|
|
73
|
+
if (data) {
|
|
74
|
+
if (data.isValid) {
|
|
75
|
+
if (data.user) {
|
|
76
|
+
if (data.user.hasPermission) {
|
|
77
|
+
return doWork(data);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**✅ Correct: early returns**
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
function process(data) {
|
|
90
|
+
if (!data) return null;
|
|
91
|
+
if (!data.isValid) return null;
|
|
92
|
+
if (!data.user) return null;
|
|
93
|
+
if (!data.user.hasPermission) return null;
|
|
94
|
+
|
|
95
|
+
return doWork(data);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Hoist Invariant Conditions
|
|
100
|
+
|
|
101
|
+
**❌ Incorrect: repeated checks**
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
for (const item of items) {
|
|
105
|
+
if (config.enableFeature && item.active) {
|
|
106
|
+
process(item);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**✅ Correct: hoist invariant**
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
if (config.enableFeature) {
|
|
115
|
+
for (const item of items) {
|
|
116
|
+
if (item.active) {
|
|
117
|
+
process(item);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Runtime Type Checks to Compile-Time
|
|
124
|
+
|
|
125
|
+
**❌ Incorrect: runtime branching**
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
function format(value: string | number) {
|
|
129
|
+
if (typeof value === "string") {
|
|
130
|
+
return value.toUpperCase();
|
|
131
|
+
} else {
|
|
132
|
+
return value.toFixed(2);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**✅ Correct: separate functions**
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
function formatString(value: string): string {
|
|
141
|
+
return value.toUpperCase();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function formatNumber(value: number): string {
|
|
145
|
+
return value.toFixed(2);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Reduce Looping
|
|
2
|
+
|
|
3
|
+
## Load Scope & Quick Navigation
|
|
4
|
+
|
|
5
|
+
Load this file when performance issues come from extra collection passes, repeated lookups, or nested iterations.
|
|
6
|
+
|
|
7
|
+
Do NOT load this file for branching structure redesign or type-modeling decisions.
|
|
8
|
+
|
|
9
|
+
Quick navigation:
|
|
10
|
+
|
|
11
|
+
- Collapse chained passes → [Chained Methods to Single Reduce](#chained-methods-to-single-reduce)
|
|
12
|
+
- Replace repeated O(n) checks → [Linear Search to O(1) Lookup](#linear-search-to-o1-lookup)
|
|
13
|
+
- Remove nested loop-side filtering → [Array Methods in Loops](#array-methods-in-loops)
|
|
14
|
+
|
|
15
|
+
## Issues
|
|
16
|
+
|
|
17
|
+
- Multiple passes over same array (`.map().filter().reduce()`)
|
|
18
|
+
- Unnecessary array creation (spreading, slicing)
|
|
19
|
+
- Array methods in loops
|
|
20
|
+
- Linear searches that could use Sets/Maps
|
|
21
|
+
- Incorrect collection type for access pattern
|
|
22
|
+
|
|
23
|
+
## Optimizations
|
|
24
|
+
|
|
25
|
+
- Combine multiple array operations into single pass
|
|
26
|
+
- Use index-based loops for performance-critical paths
|
|
27
|
+
- Replace O(n) lookups with O(1) using Set/Map
|
|
28
|
+
- Use typed arrays for numeric data
|
|
29
|
+
- Reuse arrays when function owns them (local scope, not returned/exposed)
|
|
30
|
+
|
|
31
|
+
## Examples
|
|
32
|
+
|
|
33
|
+
### Chained Methods to Single Reduce
|
|
34
|
+
|
|
35
|
+
**❌ Incorrect: two iterations**
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const result = arr.filter(predicate).map(mapper);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**✅ Correct: single iteration**
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
const result = arr.reduce((acc, curr) => (predicate(curr) ? [...acc, mapper(curr)] : acc), []);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Linear Search to O(1) Lookup
|
|
48
|
+
|
|
49
|
+
**❌ Incorrect: O(n)**
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const keys = Object.keys(someObj);
|
|
53
|
+
if (keys.includes(id)) {
|
|
54
|
+
/**/
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**✅ Correct: O(1)**
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
const keys = new Set(Object.keys(someObj));
|
|
62
|
+
if (keys.has(id)) {
|
|
63
|
+
/**/
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Array Methods in Loops
|
|
68
|
+
|
|
69
|
+
**❌ Incorrect: nested iterations**
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
for (const user of users) {
|
|
73
|
+
const active = items.filter((item) => item.userId === user.id);
|
|
74
|
+
process(active);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**✅ Correct: build lookup once**
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
const itemsByUser = new Map();
|
|
82
|
+
for (const item of items) {
|
|
83
|
+
if (!itemsByUser.has(item.userId)) {
|
|
84
|
+
itemsByUser.set(item.userId, []);
|
|
85
|
+
}
|
|
86
|
+
itemsByUser.get(item.userId).push(item);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const user of users) {
|
|
90
|
+
const active = itemsByUser.get(user.id) || [];
|
|
91
|
+
process(active);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Build Index Maps for Repeated Lookups
|
|
96
|
+
|
|
97
|
+
**❌ Incorrect: (O(n) per lookup)**
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
function processOrders(orders: Order[], users: User[]) {
|
|
101
|
+
return orders.map((order) => ({
|
|
102
|
+
...order,
|
|
103
|
+
user: users.find((u) => u.id === order.userId),
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**✅ Correct: (O(1) per lookup)**
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
function processOrders(orders: Order[], users: User[]) {
|
|
112
|
+
const userById = new Map(users.map((u) => [u.id, u]));
|
|
113
|
+
|
|
114
|
+
return orders.map((order) => ({
|
|
115
|
+
...order,
|
|
116
|
+
user: userById.get(order.userId),
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Combine Multiple Array Iterations
|
|
122
|
+
|
|
123
|
+
> Multiple .filter() or .map() calls iterate the array multiple times. Combine into one loop.
|
|
124
|
+
|
|
125
|
+
**❌ Incorrect: 3 iterations**`
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
const admins = users.filter((u) => u.isAdmin);
|
|
129
|
+
const testers = users.filter((u) => u.isTester);
|
|
130
|
+
const inactive = users.filter((u) => !u.isActive);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**✅ Correct: 1 iteration**
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const admins: User[] = [];
|
|
137
|
+
const testers: User[] = [];
|
|
138
|
+
const inactive: User[] = [];
|
|
139
|
+
|
|
140
|
+
for (const user of users) {
|
|
141
|
+
if (user.isAdmin) admins.push(user);
|
|
142
|
+
if (user.isTester) testers.push(user);
|
|
143
|
+
if (!user.isActive) inactive.push(user);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Unnecessary Array Creation
|
|
148
|
+
|
|
149
|
+
**❌ Incorrect: creates intermediate arrays**
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const result = [...arr].slice(0, 10).map(transform);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**✅ Correct: process directly**
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const result = [];
|
|
159
|
+
const len = Math.min(arr.length, 10);
|
|
160
|
+
for (let i = 0; i < len; i++) {
|
|
161
|
+
result.push(transform(arr[i]));
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Index-Based Loops for Hot Paths
|
|
166
|
+
|
|
167
|
+
**❌ Incorrect: slower iteration**
|
|
168
|
+
|
|
169
|
+
```ts
|
|
170
|
+
for (const item of largeArray) {
|
|
171
|
+
// performance-critical operation
|
|
172
|
+
processPixel(item);
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**✅ Correct: index-based**
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const len = largeArray.length;
|
|
180
|
+
for (let i = 0; i < len; i++) {
|
|
181
|
+
processPixel(largeArray[i]);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Typed Arrays for Numeric Data
|
|
186
|
+
|
|
187
|
+
**❌ Incorrect: generic array**
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const pixels = new Array(width * height);
|
|
191
|
+
for (let i = 0; i < pixels.length; i++) {
|
|
192
|
+
pixels[i] = Math.random() * 255;
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**✅ Correct: typed array**
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const pixels = new Uint8Array(width * height);
|
|
200
|
+
for (let i = 0; i < pixels.length; i++) {
|
|
201
|
+
pixels[i] = Math.random() * 255;
|
|
202
|
+
}
|
|
203
|
+
```
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# TypeScript Style & Typing Notes
|
|
2
|
+
|
|
3
|
+
## Load Scope & Quick Navigation
|
|
4
|
+
|
|
5
|
+
Load this file for naming conventions, `satisfies` vs `as const`, baseline utility types, type guards, and `import type` usage.
|
|
6
|
+
|
|
7
|
+
Do NOT load this file for branch/loop performance diagnostics when dedicated perf references are required.
|
|
8
|
+
|
|
9
|
+
Quick navigation:
|
|
10
|
+
|
|
11
|
+
- Naming/casing guidance → [Naming Conventions (Casing)](#naming-conventions-casing)
|
|
12
|
+
- `as const` vs `satisfies` tradeoffs → [as const vs satisfies](#as-const-vs-satisfies)
|
|
13
|
+
- Utility types cheat sheet → [Utility Types](#utility-types)
|
|
14
|
+
- Type guards baseline → [Type Guards](#type-guards)
|
|
15
|
+
- Type-only imports → [Import Types](#import-types)
|
|
16
|
+
|
|
17
|
+
## Naming Conventions (Casing)
|
|
18
|
+
|
|
19
|
+
Use a single, consistent casing strategy by context. Avoid mixing styles in the same scope unless required by external systems.
|
|
20
|
+
|
|
21
|
+
### Recommended Usage
|
|
22
|
+
|
|
23
|
+
- **camelCase**: variables, functions, methods, local state, parameters.
|
|
24
|
+
- **PascalCase**: types, interfaces, classes, React components.
|
|
25
|
+
- **kebab-case**: URLs, route segments, file names for static assets.
|
|
26
|
+
- **snake_case**: avoid in TS/JS; only for external APIs or database schemas.
|
|
27
|
+
|
|
28
|
+
### Examples
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// camelCase
|
|
32
|
+
const userId = "123";
|
|
33
|
+
function getUserById(id: string) {}
|
|
34
|
+
|
|
35
|
+
// PascalCase
|
|
36
|
+
type UserId = string;
|
|
37
|
+
interface UserProfile {}
|
|
38
|
+
class UserService {}
|
|
39
|
+
|
|
40
|
+
// kebab-case (URLs)
|
|
41
|
+
// /user-profile/123
|
|
42
|
+
|
|
43
|
+
// snake_case (external APIs / DB fields)
|
|
44
|
+
interface UserApiResponse {
|
|
45
|
+
user_id: string;
|
|
46
|
+
created_at: string;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Interop Guidance
|
|
51
|
+
|
|
52
|
+
When consuming snake_case data from APIs, map to camelCase at the boundary (infrastructure layer) so the rest of the app remains consistent.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## `as const` vs `satisfies`
|
|
57
|
+
|
|
58
|
+
### Summary
|
|
59
|
+
|
|
60
|
+
- **`as const`**: narrows literals and makes values deeply readonly.
|
|
61
|
+
- **`satisfies`**: validates the shape while preserving the most specific inferred type.
|
|
62
|
+
- **Combine both** when you need immutability **and** validation.
|
|
63
|
+
|
|
64
|
+
### Practical Differences
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
interface Theme {
|
|
68
|
+
colors: Record<string, string>;
|
|
69
|
+
spacing: Record<string, number>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ✅ Validate shape + keep exact keys
|
|
73
|
+
const theme = {
|
|
74
|
+
colors: { primary: "#3b82f6", secondary: "#10b981" },
|
|
75
|
+
spacing: { sm: 8, md: 16, lg: 24 },
|
|
76
|
+
} satisfies Theme;
|
|
77
|
+
|
|
78
|
+
// ✅ Immutable + validated
|
|
79
|
+
const themeConst = {
|
|
80
|
+
colors: { primary: "#3b82f6", secondary: "#10b981" },
|
|
81
|
+
spacing: { sm: 8, md: 16, lg: 24 },
|
|
82
|
+
} as const satisfies Theme;
|
|
83
|
+
|
|
84
|
+
// ⚠️ `as const` only (no validation)
|
|
85
|
+
const themeOnlyConst = {
|
|
86
|
+
colors: { primary_typo: "#3b82f6" },
|
|
87
|
+
spacing: { sm: 8 },
|
|
88
|
+
} as const;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Common Pitfall
|
|
92
|
+
|
|
93
|
+
Avoid `const x: Type = ...` for config objects because the type annotation widens literals and erases exact keys. Prefer `satisfies` so typos are caught at compile time while keeping precise inference.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Avoid TypeScript `enum`
|
|
98
|
+
|
|
99
|
+
### Why
|
|
100
|
+
|
|
101
|
+
- Adds runtime artifacts and non-idiomatic JS behavior.
|
|
102
|
+
- Creates tight coupling to enum members instead of values.
|
|
103
|
+
- Reduces flexibility when interoperating with plain strings.
|
|
104
|
+
|
|
105
|
+
### Preferred Alternatives
|
|
106
|
+
|
|
107
|
+
#### 1) Const object + derived union (recommended)
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
const ROLE = {
|
|
111
|
+
ADMIN: "ADMIN",
|
|
112
|
+
USER: "USER",
|
|
113
|
+
GUEST: "GUEST",
|
|
114
|
+
} as const;
|
|
115
|
+
|
|
116
|
+
type Role = (typeof ROLE)[keyof typeof ROLE];
|
|
117
|
+
|
|
118
|
+
function setRole(role: Role) {}
|
|
119
|
+
|
|
120
|
+
setRole(ROLE.ADMIN);
|
|
121
|
+
setRole("ADMIN");
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### 2) Literal union (small sets)
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
type Size = "sm" | "md" | "lg";
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Avoid
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
enum RoleEnum {
|
|
134
|
+
ADMIN = "ADMIN",
|
|
135
|
+
USER = "USER",
|
|
136
|
+
GUEST = "GUEST",
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Utility Types
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
Pick<User, "id" | "name">; // Select fields
|
|
146
|
+
Omit<User, "id">; // Exclude fields
|
|
147
|
+
Partial<User>; // All optional
|
|
148
|
+
Required<User>; // All required
|
|
149
|
+
Readonly<User>; // All readonly
|
|
150
|
+
Record<string, User>; // Object type
|
|
151
|
+
Extract<Union, "a" | "b">; // Extract from union
|
|
152
|
+
Exclude<Union, "a">; // Exclude from union
|
|
153
|
+
NonNullable<T | null>; // Remove null/undefined
|
|
154
|
+
ReturnType<typeof fn>; // Function return type
|
|
155
|
+
Parameters<typeof fn>; // Function params tuple
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Type Guards
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
function isUser(value: unknown): value is User {
|
|
162
|
+
return typeof value === "object" && value !== null && "id" in value && "name" in value;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Import Types
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import type { User } from "./types";
|
|
170
|
+
import { type Config, createUser } from "./utils";
|
|
171
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Type vs. Interface
|
|
2
|
+
|
|
3
|
+
## Load Scope & Quick Navigation
|
|
4
|
+
|
|
5
|
+
Load this file when deciding modeling strategy for aliases/unions/intersections versus class/declaration-merging contracts.
|
|
6
|
+
|
|
7
|
+
Do NOT load this file for runtime performance tuning.
|
|
8
|
+
|
|
9
|
+
Prefer `type` over `interface` for type aliases, unions, intersections, branded types, and functional patterns. Use `interface` only when you absolutely need:
|
|
10
|
+
|
|
11
|
+
- Declaration merging (intentional extensibility)
|
|
12
|
+
- Class implementation contracts (`implements`)
|
|
13
|
+
- Legacy API compatibility
|
|
14
|
+
|
|
15
|
+
**❌ Incorrect: interface not preferred for use case**
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
interface AvatarProps {
|
|
19
|
+
avatar: string;
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**✅ Correct: type preferred for use case**
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
type AvatarProps = { avatar: string };
|
|
27
|
+
```
|