feat: biblioteca inteligente libs/ + 5 novas skills (20 skills total)

NOVAS SKILLS:
- next-best-practices      v0.1.0  (CLEAN) — Next.js App Router, RSC, caching, data
- nextjs-patterns          v1.0.0  (CLEAN) — Next.js 15: Server Actions, route handlers
- vite                     v1.0.0  (CLEAN) — env vars, aliases, proxy, CJS compat
- uncle-bob                v1.0.0  (CLEAN) — Clean Code, SOLID, Clean Architecture
- clean-code-review        v1.0.0  (CLEAN) — naming, guard clauses, anti-patterns, refactoring
- vue                      v1.0.0  (CLEAN) — Vue framework
- vue-composition-api-best-practices v1.0.0 (CLEAN) — composables, Pinia, reactivity

BIBLIOTECA INTELIGENTE libs/ (10 dominios, 11 arquivos):
- typescript/ — TS safe + generics gotchas
- react/ — Next.js App Router + Vite config
- vue/ — Composition API + Pinia
- linux/ — System diagnostic cheatsheet
- database/ — PostgreSQL + MySQL patterns
- browser/ — Chromium CLI + E2E testing
- security/ — SAST audit (OWASP Top 10)
- best-practices/ — Clean Code + SOLID + Clean Architecture
- deploy/ — Docker multi-stack + OpenClaw ops
- + INDEX.md como guia de navegacao

.learnings/ — LRN-20260519-003 criado (biblioteca compartilhada)
This commit is contained in:
Pulse
2026-05-19 21:03:25 -03:00
parent 22d9f5b21d
commit ae39e45460
83 changed files with 13349 additions and 1 deletions
@@ -0,0 +1,96 @@
# TypeScript — Utility Types & Generics Gotchas
> Casos onde `Partial<T>`, `Omit`, `Pick`, `Extract`, etc. NÃO fazem o que você espera.
## Utility Type Gotchas
| Tipo | Armadilha | Solução |
|------|----------|---------|
| `Partial<T>` | *Shallow* — nested continua required | Criar `DeepPartial<T>` recursivo |
| `Required<T>` | Não remove `undefined` da union | Usar `NonNullable<T[K]>` por campo |
| `Omit<T, K>` | Não verifica se K existe — `Omit<User,"typo">` compila | Tipar com cuidado |
| `Pick<T, K>` | Key inexistente também compila | Mesmo cuidado |
| `Record<string, T>` | Implica TODA key existe — acesso a inexistente retorna `T`, não `T\|undefined` | Usar `Record<string, T \| undefined>` |
| `Extract<T, U>` | Retorna `never` se não houver match — silenciosamente vazio | Checar se é `never` antes |
| `ReturnType<typeof fn>` | Com overload pega só a última signature | Evitar overloads ou tipar retorno manualmente |
| `NonNullable<T>` | Remove `null` E `undefined` — às vezes só quer um | Usar `Exclude<T, null>` ou `Exclude<T, undefined>` |
| `Awaited<T>` | Desempacota recursivamente — surpresa com `Promise<Promise<T>>` | Cuidado com promises encadeadas |
## Generics — Armadilhas Práticas
```ts
// ❌ <T = any> foge do any para todo o código
function parse<T = any>(raw: string): T { ... }
// ✅ Deixe o caller fornecer o tipo, ou use unknown
function parse<T>(raw: string): T { ... }
// ou
function parse(raw: string): unknown { ... }
// ❌ <T extends object> permite arrays
function merge<T extends object>(a: T, b: T): T { ... }
merge([1, 2], [3, 4]) // compila, mas não deve
// ✅ Use Record<string, unknown> para objetos puros
function merge<T extends Record<string, unknown>>(a: T, b: T): T { ... }
// ❌ <T extends string> com literal infere string, não o literal
function prefix<T extends string>(p: T) { ... }
prefix("http") // T é "http", não "http" literal nesse contexto
// ✅ Use const assertion para preservar literais
const urls = ["/api", "/auth"] as const; // readonly ["/api", "/auth"]
```
## `keyof` em Função Genérica
```ts
// ❌ keyof T em função genérica é sempre string | number | symbol
function getProp<T, K extends keyof T>(obj: T, key: K) { ... }
// ✅ Para objeto puro, restringir:
function getProp<T extends Record<string, unknown>, K extends keyof T>(
obj: T, key: K
): T[K] {
return obj[key];
}
```
## Covariância e Contravariância
```ts
// ❌ Arrays são COVARIANTES — Dog[] atribuível a Animal[] mas push(Cat) quebra runtime
const dogs: Dog[] = [];
const animals: Animal[] = dogs; // ✅ compila
animals.push(new Cat()); // 🚨 runtime error
// ❌ Parâmetros de função são CONTRAVARIANTES
type Handler = (animal: Animal) => void;
const dogHandler: Handler = (dog: Dog) => { ... }; // ❌ não compila
// (Animal) espera receber Animal, não só Dog
```
## Mapped Types — Preservando Modificadores
```ts
// ❌ { [K in keyof T]: T[K] } — PERDE readonly e optional
type StrictClone<T> = { [K in keyof T]: T[K] };
// → { readonly name: string } vira { name: string }
// ✅ Preservar modificadores com -readonly, -?
type Preserve<T> = { -readonly [K in keyof T]: T[K] };
type Optionalize<T> = { -? [K in keyof T]: T[K] };
```
## Conditional Types — Distributividade
```ts
// ✅ Distribui sobre union
type NonNullableValues<T> = T extends null | undefined ? never : T;
type Result = NonNullableValues<string | null | number | undefined>;
// Result = string | number ← distribuiu corretamente
// ❌ Para não distribuir, usar [T] (tupla wrapper)
type WrapNonNullable<T> = [T] extends [null | undefined] ? never : T;
// Não distribui — útil quando a distribuição causa comportamento inesperado
```
@@ -0,0 +1,76 @@
# TypeScript — Safe Patterns
> Extraído de skills: typescript v1.0.2, generics.md, utility-types.md, declarations.md
## Anti-pattern: Evite `any`
- Use `unknown` quando não souber o tipo — força narrowing antes do uso
- Respostas de API: tipar ou `unknown`, nunca `any`
## Narrowing Failures
| Padrão | Problema | Solução |
|--------|---------|---------|
| `filter(Boolean)` | Não narrovia | `.filter((x): x is T => Boolean(x))` |
| `Object.keys(obj)` | Retorna `string[]` | Usar `keyof typeof obj` é intencional — objetos podem ter chaves extras |
| `Array.isArray()` | Narrovia para `any[]` | Pode precisar assertion de tipo de elemento |
| `useState<User>()` | Infere `User \| undefined` | Tratar undefined inicial |
| `Promise.all([a(), b()])` | Infere tupla só com `as const` | Usar `as const` na array |
## Literal Type Traps
- `let x = "hello"``string`. Use `const` ou `as const` para literal
- Propriedades de objeto alargam: `{ status: "ok" }``status: string`
- Retorno de função alarga — anote explicitamente para retornos literais
## `satisfies` vs Type Annotation
```ts
// ❌ Perde info literal
const config: RouteConfig = { path: "/home", method: "GET" };
// ✅ Mantém literal + valida compatibilidade
const config = { path: "/home", method: "GET" } satisfies RouteConfig;
```
> Preferir `satisfies` para config objects.
## Strict Null Handling
- `?.` retorna `undefined`, não `null`
- `??` captura só `null`/`undefined`; `||` captura tudo falsy (`0`, `""`, `false`)
- `!` (non-null assertion) — último recurso; preferir narrowing ou early return
## Generics — Armadilhas Comuns
- `<T = any>` foge do `any` — restringe todo o código
- `<T extends object>` permite arrays — usar `Record<string, unknown>` para objetos puros
- Arrays são covariantes — `Dog[]` atribuível a `Animal[]` mas `push(Cat)` quebra em runtime
- Parâmetros de função são contravariantes — `(Animal) => void` NÃO é atribuível a `(Dog) => void`
- `Partial<T>` e `Required<T>` são *shallow* — não afetam nested:
```ts
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
```
## Discriminated Unions
```ts
type Result<T> =
| { ok: true; data: T }
| { ok: false; error: string };
function handle(r: Result<User>) {
if (r.ok) {
console.log(r.data.name); // ✅ T automaticamente
} else {
console.log(r.error); // ✅ narrowed
}
}
```
- Switch exaustivo: `default: const _never: never = x` → erro de compilação se caso faltar
## Module Boundaries
- `import type` — stripped em runtime, evita problemas de bundler
- Re-export types: `export type { X }` — previne dependência runtime acidental
- `.d.ts` augmentation: usar `declare module` com path exato do módulo
## Declaration File Gotchas
- `declare module "x"` precisa de path EXATO — `"lodash"``"lodash/index"`
- `interface` pode ser mergeado de outros arquivos — `type` não pode
- Export default em `.d.ts` é problemático — preferir named exports