기본 패턴
ts
function isStringArray(value: unknown): value is string[] {
return Array.isArray(value) && value.every((item) => typeof item === "string");
}
function assertHasId(value: unknown): asserts value is { id: string } {
if (!value || typeof value !== "object" || !("id" in value)) {
throw new Error("id is required");
}
}설명
- TypeScript는 타입 검사 도구이지만, 실제 입력값은 런타임에 들어옵니다. API 응답,
JSON.parse, 브라우저 입력 같은 값은 컴파일러가 미리 보장할 수 없습니다. - custom type predicate는 "이 함수가 true를 반환했다면 value를 특정 타입으로 봐도 된다"는 사실을 타입 시스템에 알려주는 방식입니다. 반환형에
value is SomeType이 들어갑니다. - assertion function은 더 강한 버전입니다. 함수가 정상 종료했다면 값이 특정 타입 조건을 만족한다고 간주하게 만들고, 실패하면 예외를 던집니다. 그래서 validation 이후 코드를 더 간결하게 만들 수 있습니다.
- 핵심은 타입 단언(
as)으로 억지로 통과시키지 말고, 런타임 검사와 타입 좁히기를 연결하는 것입니다. 이 연결이 있어야 안전한 입력 검증 코드가 됩니다. - 이런 함수는 결국 프로젝트의 작은 schema 역할을 합니다. 로컬 helper로 끝날 수도 있고, 더 커지면 validation 라이브러리로 옮겨갈 수도 있습니다.
빠른 정리
| 패턴 | 의미 |
|---|---|
value is T | true일 때 T로 좁힘 |
asserts value is T | 함수가 끝나면 T로 간주 |
| 잘 맞는 입력 | API 응답, 사용자 입력, 파싱 결과 |
| 피해야 할 방식 | 근거 없는 as 단언 |
주의할 점
predicate나 assertion function 이름만 그럴듯하고 내부 검사가 부실하면, 컴파일러만 속이고 런타임 안전성은 얻지 못합니다. "무엇을 확인했는지"가 실제 타입 보장 범위와 맞아야 합니다.
참고 링크
1 sources