외부 API나 배열 인덱스 접근에서는 값이 undefined가 될 가능성이 있어, 타입상 그대로는 다루기 어렵다. Non-null assertion을 사용해 런타임 체크와 타입 좁히기를 동시에 달성한다.
코드
function assertIsDefined<T>(value: T): asserts value is NonNullable<T> { if (value === undefined || value === null) { throw new Error(`Expected 'value' to be defined, but received ${value}`); }}
function nonNull<T>(value: T): NonNullable<T> { assertIsDefined(value); return value;}사용 예시
배열 요소 안전하게 가져오기
const arr = [1, 2, 3];const value = arr[10]; // number | undefined
// 타입 에러를 피할 수 없음console.log(value.toFixed()); // Error: Object is possibly 'undefined'
// nonNull 사용const safeValue = nonNull(arr[10]);// NonNullable<number>로 추론됨console.log(safeValue.toFixed()); // OKAPI 응답 검증
interface User { name: string;}
async function getUser(id: string): Promise<User> { const response = await fetch(`/api/users/${id}`); const user = await response.json() as User | undefined;
// 응답이 비어있으면 에러 assertIsDefined(user);
// 이 시점에서 user는 User 타입으로 다룰 수 있음 return user;}! 연산자와의 차이
TypeScript에는 value!라는 non-null assertion 연산자도 있지만, 이는 런타임 체크를 수행하지 않는다. assertion 함수를 사용하면 런타임에 값을 검증하면서 타입도 좁힐 수 있다.
주의사항
assertion 함수는 값이 정말로 존재한다고 확신할 수 있는 경우에 사용한다. 무턱대고 사용하면 런타임 에러가 발생한다. 특히 배열의 인덱스 접근에서는 미리 length 체크를 고려해야 한다.
hsb.horse