Zbudowałem sprawdzacz typów, który sprawił, że AI przestało mnie okłamywać
AI używa `any`, żeby uciec przed błędem typów. Dodaje eslint-disable. Kłamie ci w oczy. Oto jak naprawiliśmy tę pętlę sprzężenia zwrotnego.
AI nie okłamuje cię, bo chce. Okłamuje cię, bo na to pozwalasz.
Zepsuta pętla sprzężenia zwrotnego
Poproś Claude Code o dodanie funkcji. Robi to. Uruchom ESLint - przechodzi. Uruchom TypeScript - błędy. Poproś Claude Code o naprawienie błędów TypeScript. Robi to. Uruchom ESLint - teraz to się nie udaje. Tam i z powrotem. Trzy iteracje. AI jest pewne siebie na każdym kroku. Za każdym razem: "To jest naprawione."
Nigdy nie było naprawione.
To była gra w kreta z narzędziem, które uruchamia jeden linter na raz i nigdy nie widzi pełnego obrazu.
AI naprawia błąd TypeScript, pisząc jedną linię i mówi ci: "Błąd typów jest rozwiązany."
1const result = data as unknown as MyExpectedType;Tak. Technicznie. Tak jak zaklejenie czujnika dymu taśmą rozwiązuje alarm pożarowy.
To właśnie po to zbudowałem @next-vibe/checker.
Problem z `any`
Dlaczego 98% bezpieczeństwa typów to to samo co 0%
System typów TypeScript to graf. Każdy typ przepływa od definicji do użycia. Jeśli masz funkcję, która zwraca `string`, wywołujący wie, że to string. Cały łańcuch jest sprawdzany.
Jeden typ `any` rozprzestrzenia się przez graf, korumpując wnioskowanie typów poniżej
`any` to dziura w grafie.
Zmienna typowana jako `any` mówi kompilatorowi: zatrzymaj sprawdzanie tutaj. Nie tylko dla tej zmiennej - dla wszystkiego, co dotyka tej zmiennej. Błąd nie pojawia się przy `any`. Pojawia się trzy pliki dalej, gdy niezwiązany refactoring psuje założenie, które nigdy nie było egzekwowane.
0
błędy TypeScript
47
użycia `any`
Zero błędów TypeScript nie znaczy nic, jeśli masz 47 niezweryfikowanych użyć `any`.
`as unknown as Whatever` jest gorsze. To podwójne twierdzenie typowe. Mówisz kompilatorowi: wiem, że to jest błędne, i mimo to się przez to przekonuję. To ulubiona furtka AI.
Zakazane wzorce w tej bazie kodu:
Nie ostrzeżenia. Błędy. Sprawdzenie się nie udaje. Claude Code musi naprawić podstawową przyczynę lub nie może dostarczyć.
Powód, dla którego są to błędy, a nie ostrzeżenia, jest psychologiczny tak samo jak techniczny. Modele AI traktują ostrzeżenia jako opcjonalne. Błędy zamykają pętlę.
Przedstawiamy @next-vibe/checker
Jedno polecenie. Trzy narzędzia. Brak furtek.
1$ vibe checkTo jest polecenie. Jedno polecenie. Uruchamia trzy narzędzia równolegle i daje ci jedną ujednoliconą listę błędów.
Oxlint
Linter oparty na Rust. Setki reguł. Działa w milisekundach nawet na dużych bazach kodu.
ESLint
Rzeczy, których Oxlint jeszcze nie robi: lint haków React, reguły kompilatora React, sortowanie importów.
TypeScript
Pełne sprawdzanie typów. Nie tylko plik, który edytujesz - cały graf.
Ujednolicona lista błędów
Jedno wyjście. Naprawiaj, aż będzie czysto.
Na tej bazie kodu - 4400 plików - pełne TypeScript zajmuje około 12 sekund. Oxlint jest poniżej sekundy. ESLint to kilka sekund. Równoległość sprowadza to do 12.
Udostępnia również polecenie `vibe-check mcp`, które uruchamia serwer MCP z narzędziem `check`. AI nie uruchamia polecenia powłoki - wywołuje narzędzie, które zwraca ustrukturyzowane dane błędów. Paginacja wbudowana. Filtrowanie według ścieżki.
Niestandardowe wtyczki
Linter to dokumentacja. I jest egzekwowany.
Wtyczka jsx-capitalization
Flaguje elementy JSX pisane małymi literami, a komunikat o błędzie mówi ci dokładnie, co zamiast tego zaimportować:
Nie napisałem dokumentacji mówiącej Claude Code, żeby używało `next-vibe-ui`. Nie dodałem tego do systemowego promptu. Za pierwszym razem, gdy Claude Code pisze `<div>` w komponencie, sprawdzacz wyrzuca błąd. Komunikat o błędzie zawiera dokładną ścieżkę importu. Claude Code czyta błąd, stosuje poprawkę i zapamiętuje konwencję.
Wtyczka restricted-syntax
Zakazuje trzech rzeczy:
Instrukcje `throw`
Komunikat o błędzie mówi: "Zamiast tego użyj właściwych wzorców `ResponseType<T>`." Claude Code na to trafia, czyta to, szuka `ResponseType` i przyjmuje właściwy wzorzec obsługi błędów dla reszty zadania.
nagi typ `unknown`
"Zastąp 'unknown' istniejącym typowanym interfejsem. Dostosuj się do typów w bazie kodu, zamiast konwertować lub odtwarzać." To powstrzymuje Claude Code przed pisaniem generycznych furtek typowych.
nagi typ `object`
`object` jest prawie zawsze błędny. Albo znasz kształt - napisz interfejs - albo masz `Record<string, SomeType>`. Surowy `object` to sygnał, że AI się poddało.
Zakazane wzorce
1const result = response as unknown as MyType;1const result: MyType = parseResponse(response);1function foo(x: any): any { return x.data; }1function foo<T>(response: ResponseType<T>): T | null {
2 if (!response.success) return null;
3 return response.data;
4}1throw new Error("Something failed");1return fail({
2 message: t("errors.server.title"),
3 errorType: ErrorResponseTypes.INTERNAL_ERROR,
4});Demo na żywo: wzorzec 3 rund
Obserwuj, jak Claude Code trafia na sprawdzacz trzy razy przed znalezieniem właściwego typu
Runda 1 - AI pisze `any`
Zapytaj Claude Code: "Napisz funkcję pomocniczą, która przyjmuje surowy obiekt odpowiedzi API i wyciąga pole danych. Odpowiedź może mieć różne kształty - użyj whatever type makes this work."
Claude Code pisze proste rozwiązanie:
1export function parseApiResponse(response: any): any {
2 return response.data;
3}1 1:37 error Unexpected any. typescript/no-explicit-any
2 1:44 error Unexpected any. typescript/no-explicit-any
3
42 errors found.Runda 2 - AI próbuje `unknown`
Obserwuj, co robi dalej. To jest ważna część. Próbuje następnej drogi ucieczki:
Sprawdzacz zna ten trik.
1export function parseApiResponse(response: unknown): unknown {
2 return (response as Record<string, unknown>).data;
3}1 1:37 error Replace 'unknown' with typed interface. restricted-syntax
2 1:44 error Replace 'unknown' with typed interface. restricted-syntax
3 1:56 error Replace 'unknown' with typed interface. restricted-syntax
4
53 errors found.Runda 3 - AI znajduje prawdziwy typ
Teraz Claude Code robi to, co powinno zrobić jako pierwsze. Patrzy, jak istniejące odpowiedzi API są typowane w tej bazie kodu. Znajduje `ResponseType<T>`.
Zero błędów. I funkcja jest teraz faktycznie poprawna.
1import type { ResponseType } from "@/response-type";
2
3export function parseApiResponse<T>(
4 response: ResponseType<T>
5): T | null {
6 if (!response.success) return null;
7 return response.data;
8}1 Oxlint: 0 errors
2 ESLint: 0 errors
3 TypeScript: 0 errors
4
50 errors found.Sprawdzacz tego nie napisał. Ale sprawdzacz zapobiegł skrótowi dwa razy, dopóki Claude Code nie musiało się zmierzyć z faktycznym problemem.
Połączenie z endpointem
Jeden schemat Zod - czterech konsumentów poniżej
Każdy endpoint ma plik definicji. Ten plik zawiera jeden schemat Zod dla żądania i jeden dla odpowiedzi.
Klucz `schema` to walidator Zod. Ten sam schemat Zod staje się:
1name: requestField(st, {
2 schema: z.string().min(1).max(255),
3 label: "name",
4 description: "description",
5 placeholder: "placeholder",
6}),Regułą walidacji na endpoincie web API
Typem TypeScript dla parametru wejściowego hooka React
Flagą `--name` w CLI z zastosowanymi ograniczeniami min/max
Opisem parametru w schemacie narzędzia AI
Tu zwykle zabija cię dryf. Aktualizujesz API. Zapominasz zaktualizować schemat narzędzia AI. AI wywołuje endpoint ze starymi nazwami parametrów. Cicho się nie udaje.
Gdy jest jeden schemat, nie ma nic do synchronizowania.
I ponieważ sprawdzacz TypeScript też na tym działa - jeśli zmienisz schemat w sposób, który psuje wnioskowany typ poniżej, dostajesz błąd kompilatora. Schemat narzędzia AI jest sprawdzany typowo. Flagi CLI są sprawdzane typowo. Hook React jest sprawdzany typowo.
245
245 endpointów
0
Zero `any`
0
Zero rzutowań `unknown`
0
Zero `@ts-expect-error`
Nie przez konwencję. Przez sprawdzacz.
Zainstaluj @next-vibe/checker
Działa na każdym projekcie TypeScript. Nie tylko next-vibe.
Sprawdzacz jest dostępny jako samodzielny pakiet npm. Działa na każdym projekcie TypeScript - nie tylko NextVibe. Nie potrzebujesz żadnej innej części frameworka.
1bun add -D @next-vibe/checker\n# or\nnpm install -D @next-vibe/checkerNastępnie uruchom:
1vibe-check config # scaffold check.config.ts\nvibe-check # run all checks\nvibe-check --fix # auto-fix linting issuesIntegracja MCP
Dodaj go do konfiguracji MCP Claude Code lub Cursor. Teraz Claude Code wywołuje `check` jako narzędzie, a nie polecenie powłoki. Ustrukturyzowane błędy. Paginowane. Filtrowane według ścieżki.
1{
2 "mcpServers": {
3 "vibe-check": {
4 "command": "vibe-check",
5 "args": ["mcp"],
6 "env": { "PROJECT_ROOT": "/path/to/project" }
7 }
8 }
9}Na stronie npm jest też prompt migracyjny. Skopiuj go do Claude Code lub Cursor, a przejrzy twoją bazę kodu, skonfiguruje sprawdzacz i zmigruje cię do zakazanych wzorców.
To jest open source. GPL-3.0 dla frameworka, MIT dla pakietu sprawdzacza.
Zbuduj system tak, żeby kłamstwo było niemożliwe
Przedtem:
Programowanie wspomagane AI było negocjacją. Napraw lint. Och, teraz typy są zepsute. Napraw typy. Teraz jest `any`, którego nie zauważyłeś. Napraw to. Uruchom trzy oddzielne narzędzia. Uzyskaj trzy oddzielne opinie. Nigdy nie wiesz, czy to naprawdę czyste.
Potem:
Jedno polecenie. Jeden tryb awarii. Albo przechodzi, albo nie. AI wie dokładnie, co musi naprawić, ponieważ błędy mówią mu dokładnie, co jest nie tak i co zamiast tego zrobić. Żadnych negocjacji.
Zbuduj system tak, żeby kłamstwo było niemożliwe. Do tego służy sprawdzacz typów.
Rozmawiaj, twórz i łącz się - tekst, obrazy, wideo i muzyka
Prywatna AI z 119 modelami - czat, obrazy, wideo i muzyka
Platforma
© 2026 unbottled.ai. Wszelkie prawa zastrzeżone.