Repository navigation
Expand file tree
/
Copy pathskill.ts
More file actions
84 lines (82 loc) · 3.07 KB
/
Copy pathskill.ts
File metadata and controls
84 lines (82 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { reference, render } from '@contentful/skill-kit';
export default reference({
name: 'ts-patterns',
version: '1.0.0',
description:
'TypeScript patterns and idioms reference. Use when writing TypeScript and need a quick ' +
'refresher on generics, discriminated unions, builder patterns, or error handling.',
argumentHint: '[topic]',
paths: '**/*.ts',
})
.topic('generics', {
label: 'Generics cheat sheet — constraints, conditional types, mapped types, infer',
content: ({ refs }) => refs.load('generics.md'),
})
.topic('discriminated-unions', {
label: 'Discriminated unions — type narrowing with literal discriminants',
content: () =>
[
'# Discriminated Unions',
'',
'Use a literal `type` or `kind` field to narrow union members:',
'',
render.code(
[
'type Shape =',
" | { kind: 'circle'; radius: number }",
" | { kind: 'rect'; width: number; height: number };",
'',
'function area(s: Shape): number {',
' switch (s.kind) {',
" case 'circle': return Math.PI * s.radius ** 2;",
" case 'rect': return s.width * s.height;",
' }',
'}',
].join('\n'),
'typescript',
),
'',
'TypeScript narrows the type inside each `case` branch automatically.',
'Exhaustiveness: add `default: return s satisfies never;` to catch missing cases.',
].join('\n'),
})
.topic('builder-pattern', {
label: 'Builder pattern — fluent APIs with type accumulation',
content: () =>
[
'# Builder Pattern',
'',
'Return `this` from each method for chaining. Use generics to accumulate type information:',
'',
render.code(
[
'class QueryBuilder<T> {',
' where(clause: string): QueryBuilder<T> { /* ... */ return this; }',
' select<U>(...cols: (keyof T)[]): QueryBuilder<Pick<T, typeof cols[number]>> {',
' return this as any;',
' }',
' build(): Query<T> { /* ... */ }',
'}',
].join('\n'),
'typescript',
),
'',
'Each `.select()` narrows the result type. `.build()` produces the final typed query.',
].join('\n'),
})
.topic('error-handling', {
label: 'Error handling — Result types, custom errors, exhaustive matching',
content: () => {
const patterns = render.table(
[
{ pattern: 'try/catch', use: 'External APIs, I/O', note: 'Catch specific error types' },
{ pattern: 'Result<T, E>', use: 'Domain logic', note: 'Forces caller to handle both paths' },
{ pattern: 'Custom Error class', use: 'Typed error codes', note: 'Extend Error, add fields' },
{ pattern: 'never in switch', use: 'Exhaustive matching', note: 'Compile-time missing-case check' },
],
{ columns: ['pattern', 'use', 'note'] },
);
return ['# Error Handling Patterns', '', patterns].join('\n');
},
})
.build();