void와 never는 TypeScript에서 다른 타입입니다:
예제:
function log(message: string): void { console.log(message); } function throwError(message: string): never { throw new Error(message); } function infinite(): never { while (true) {} }
never는 종종 switch-case에서 타입의 완전성을 검사하는 데 사용됩니다:
type Shape = { kind: 'circle' } | { kind: 'square' }; function getArea(shape: Shape) { switch (shape.kind) { case 'circle': return 1; case 'square': return 2; default: const _exhaustive: never = shape; // 여기서 컴파일러는 case가 빠졌으면 알려줍니다. } }
void와 never가 함수의 반환 타입으로 서로 교환 가능할 수 있나요?
답변: 아닙니다. void 타입의 함수는 undefined를 반환하거나 아무것도 반환하지 않지만 실행을 완료합니다. never 타입의 함수는 결코 성공적으로 실행을 완료하지 않습니다(오류를 발생시키거나 무한 루프에 빠집니다).
예제:
const fn: () => never = () => { // return; // 오류: 'never'로 선언된 함수는 반환해서는 안 됩니다. };
역사
분석 시스템에서 유효성 검사 함수의 반환 타입을 void로 지정했지만 항상 예외를 throw했습니다. 결과적으로 개발자들은 이 함수가 "돌아올" 수 있다고 생각하고 추가 검사를 하지 않아서 오류 처리를 놓치고 호출 체인을 잘못 구현하게 되었습니다.
역사
TypeScript 프로젝트에서 명확하게 타입이 지정된 반환 타입을 기대하는 함수를 void가 아닌 never로 정의했습니다. 이로 인해 never로 타입이 지정된 콜백을 사용하는 함수 호출 시 컴파일 오류와 API 호환성 상실이 발생했습니다.
역사
백엔드 모듈에서는 예외를 void 반환 타입을 가진 함수를 통해 던졌습니다. TypeScript로 마이그레이션한 후 이 함수 호출 이후 코드 범위를 벗어난 것에 대해 컴파일러가 경고하지 않아서 "도달할 수 없는" 코드가 여러 줄 생겼습니다. 그리고 반환 타입을 never로 변경함으로써 그러한 장소를 발견하고 코드를 더 깔끔하게 하고 논리적 오류를 피할 수 있었습니다.