Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Strict TypeScript rules. Use when writing ANY TypeScript.
.claude/skills/aiskillstore-typescript-strict/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 1372% | 0% |
| case-22 | ✓→✗ | ▼ Worse | 74% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 90% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 153% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 232% | 0% |
TypeScript 엄격 모드와 타입 안전성을 강제하는 스킬입니다.
> TypeScript 5.x에서 strict 모드가 새 프로젝트의 기본값으로 권장됨 > "any 사용은 TypeScript를 쓰는 의미를 없앤다"
| 규칙 | 상태 | 설명 | |------|------|------| | strict: true | 🔴 필수 | 모든 엄격 검사 활성화 | | any 금지 | 🔴 필수 | unknown 또는 제네릭 사용 | | // @ts-ignore 금지 | 🔴 필수 | 타입 에러 해결 필수 | | as 캐스팅 최소화 | 🟡 권장 | 타입 가드 우선 |
json{ "compilerOptions": { // 🔴 필수: strict 플래그 "strict": true, // strict가 포함하는 옵션들 (개별 비활성화 금지) // "strictNullChecks": true, // "strictFunctionTypes": true, // "strictBindCallApply": true, // "strictPropertyInitialization": true, // "noImplicitAny": true, // "noImplicitThis": true, // "alwaysStrict": true, // 🔴 추가 필수 옵션 "noUncheckedIndexedAccess": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noUnusedLocals": true, "noUnusedParameters": true, // 🟡 권장 옵션 "exactOptionalPropertyTypes": true, "noPropertyAccessFromIndexSignature": true } }
typescript// ❌ BAD: any 사용 function processData(data: any) { return data.value; // 런타임 에러 가능 } const result: any = fetchData(); result.nonExistent(); // 컴파일 통과, 런타임 에러
typescript// ✅ GOOD: unknown + 타입 가드 function processData(data: unknown) { if (isValidData(data)) { return data.value; } throw new Error('Invalid data'); } function isValidData(data: unknown): data is { value: string } { return typeof data === 'object' && data !== null && 'value' in data; } // ✅ GOOD: 제네릭 사용 function processData<T extends { value: string }>(data: T) { return data.value; }
typescript// Before function parse(json: string): any { return JSON.parse(json); } // After function parse(json: string): unknown { return JSON.parse(json); } // 사용 시 타입 체크 필요 const result = parse('{"name": "test"}'); if (isUser(result)) { console.log(result.name); // 안전 }
typescript// ❌ BAD: 위험한 타입 단언 const user = response.data as User; user.name.toUpperCase(); // null이면 에러 // ❌ BAD: 이중 단언 (매우 위험) const value = data as unknown as TargetType;
typescript// ✅ GOOD: 타입 가드 function isUser(data: unknown): data is User { return ( typeof data === 'object' && data !== null && 'name' in data && typeof (data as { name: unknown }).name === 'string' ); } if (isUser(response.data)) { response.data.name.toUpperCase(); // 안전 } // ✅ GOOD: Zod 스키마 검증 import { z } from 'zod'; const UserSchema = z.object({ name: z.string(), email: z.string().email(), }); const user = UserSchema.parse(response.data);
typescript// ❌ BAD: null 체크 없음 function getLength(str: string | null) { return str.length; // 에러: null일 수 있음 } // ✅ GOOD: null 체크 function getLength(str: string | null) { if (str === null) return 0; return str.length; } // ✅ GOOD: 옵셔널 체이닝 function getLength(str: string | null) { return str?.length ?? 0; }
typescript// noUncheckedIndexedAccess: true 일 때 const arr = [1, 2, 3]; const first = arr[0]; // number | undefined // ❌ BAD: undefined 체크 없음 console.log(first.toFixed(2)); // 에러 // ✅ GOOD: undefined 체크 if (first !== undefined) { console.log(first.toFixed(2)); } // ✅ GOOD: 논리 연산자 console.log(arr[0]?.toFixed(2) ?? 'N/A');
typescript// ❌ BAD: 반환 타입 추론 의존 function fetchUser(id: string) { return api.get(`/users/${id}`); // 반환 타입? } // ✅ GOOD: 명시적 반환 타입 async function fetchUser(id: string): Promise<User> { return api.get(`/users/${id}`); }
typescript// ✅ GOOD: 오버로드로 정확한 타입 function process(input: string): string; function process(input: number): number; function process(input: string | number): string | number { if (typeof input === 'string') { return input.toUpperCase(); } return input * 2; } const str = process('hello'); // string const num = process(42); // number
typescript// ❌ BAD: any 사용 function first(arr: any[]): any { return arr[0]; } // ✅ GOOD: 제네릭 function first<T>(arr: T[]): T | undefined { return arr[0]; } // ✅ GOOD: 제약 있는 제네릭 function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }
json{ "extends": [ "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking" ], "rules": { "@typescript-eslint/no-explicit-any": "error", "@typescript-eslint/no-unsafe-assignment": "error", "@typescript-eslint/no-unsafe-member-access": "error", "@typescript-eslint/no-unsafe-call": "error", "@typescript-eslint/no-unsafe-return": "error", "@typescript-eslint/explicit-function-return-type": "warn", "@typescript-eslint/no-non-null-assertion": "warn", "@typescript-eslint/prefer-nullish-coalescing": "warn" } }
typescript// 🔴 절대 금지 // @ts-ignore // @ts-nocheck // @ts-expect-error (테스트 제외) // eslint-disable @typescript-eslint/no-explicit-any // 🔴 금지: any 캐스팅 data as any (data as unknown) as TargetType // 🟡 최소화 data! // non-null assertion data as Type // 타입 가드 우선
bash# TypeScript 초기화 npx tsc --init # strict 활성화 확인 grep -n "strict" tsconfig.json
bash# 1. strict 활성화 # tsconfig.json: "strict": true # 2. 에러 확인 npx tsc --noEmit # 3. 점진적 수정 # - any → unknown # - as → 타입 가드 # - null 체크 추가
타입 안전성 체크:
- [ ] any 사용하지 않음
- [ ] @ts-ignore 없음
- [ ] 타입 단언 최소화
- [ ] null 체크 적절함strict: true 설정noUncheckedIndexedAccess: true 설정| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 2,599 | 20,798 | +700% | 1 | 1 | 0% | 352 | 5,180 | +1372% | 0 | 0 | — |
case-02 | pass→pass | 15,938 | 13,100 | -18% | 1 | 1 | 0% | 2,104 | 4,003 | +90% | 0 | 0 | — |
case-03 | pass→pass | 9,643 | 15,536 | +61% | 1 | 1 | 0% | 1,652 | 4,177 | +153% | 0 | 0 | — |
case-04 | pass→pass | 10,865 | 8,234 | -24% | 1 | 1 | 0% | 1,085 | 3,605 | +232% | 0 | 0 | — |
case-05 | pass→pass | 18,081 | 18,061 | -0% | 1 | 1 | 0% | 2,274 | 4,601 | +102% | 0 | 0 | — |
case-06 | pass→pass | 22,799 | 19,112 | -16% | 1 | 1 | 0% | 3,433 | 5,235 | +52% | 0 | 0 | — |
case-07 | pass→pass | 11,084 | 10,840 | -2% | 1 | 1 | 0% | 1,169 | 3,244 | +178% | 0 | 0 | — |
case-08 | pass→pass | 19,494 | 11,559 | -41% | 1 | 1 | 0% | 2,948 | 3,471 | +18% | 0 | 0 | — |
case-09 | pass→pass | 10,027 | 8,114 | -19% | 1 | 1 | 0% | 875 | 3,687 | +321% | 0 | 0 | — |
case-10 | pass→pass | 16,693 | 15,604 | -7% | 1 | 1 | 0% | 2,241 | 4,572 | +104% | 0 | 0 | — |
case-11 | pass→pass | 12,067 | 10,748 | -11% | 1 | 1 | 0% | 1,218 | 3,120 | +156% | 0 | 0 | — |
case-12 | pass→pass | 8,261 | 8,497 | +3% | 1 | 1 | 0% | 502 | 2,737 | +445% | 0 | 0 | — |
case-13 | pass→pass | 24,073 | 14,839 | -38% | 1 | 1 | 0% | 1,942 | 4,128 | +113% | 0 | 0 | — |
case-14 | pass→pass | 12,320 | 15,751 | +28% | 1 | 1 | 0% | 1,256 | 3,251 | +159% | 0 | 0 | — |
case-15 | pass→pass | 9,760 | 9,935 | +2% | 1 | 1 | 0% | 860 | 3,006 | +250% | 0 | 0 | — |
case-16 | pass→pass | 16,042 | 17,059 | +6% | 1 | 1 | 0% | 1,947 | 4,517 | +132% | 0 | 0 | — |
case-17 | pass→pass | 14,868 | 15,779 | +6% | 1 | 1 | 0% | 1,661 | 4,105 | +147% | 0 | 0 | — |
case-18 | pass→pass | 6,164 | 6,706 | +9% | 1 | 1 | 0% | 1,217 | 3,512 | +189% | 0 | 0 | — |
case-19 | fail→fail | 11,426 | 6,733 | -41% | 1 | 1 | 0% | 1,190 | 3,446 | +190% | 0 | 0 | — |
case-20 | pass→pass | 14,601 | 13,390 | -8% | 1 | 1 | 0% | 790 | 3,595 | +355% | 0 | 0 | — |
case-21 | pass→pass | 22,130 | 17,909 | -19% | 1 | 1 | 0% | 2,135 | 4,815 | +126% | 0 | 0 | — |
case-22 | pass→fail | 33,013 | 23,386 | -29% | 1 | 1 | 0% | 2,725 | 4,736 | +74% | 0 | 0 | — |
case-23 | pass→pass | 16,239 | 13,058 | -20% | 1 | 1 | 0% | 2,125 | 4,541 | +114% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of 0 percentage points is the difference between those two pass rates over the 23 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.