사용자 정의 타입 안전장치(user-defined type guard)
불(boolean)을 반환하는 함수 중 단순히 "이 함수는 boolean을 반환한다"라고 하고 끝내기엔 아쉬운 게 있을 수 있습니다.
예를 들어 전달한 인수가 string인지 아닌지를 판단하는 함수를 구현한다고 가정하겠습니다.
function isString(a: unknown): boolean {
return typeof a === "string";
}
isString("a"); // true
isString([4]); // false
지금까진 아무런 문제가 없습니다. 하지만 isString 실제로 호출하면 어떤 일이 일어날까요?
function isString(a: unknown): boolean {
return typeof a === "string";
}
isString("a"); // true
isString([4]); // false
function parseInput(input: string | number){
let formattedInput: string
if(isString(input)){
formattedInput = input.toUpperCase() // 'number' 형식에 'toUpperCase' 속성이 없습니다.ts(2339)
}
}
일반 타입 정제에선 typeof가 잘 동작했는데 위의 코드는 왜 동작하지 않을까요?
타입 정제는 강력하지만 현재 영역(유효 범위)에 속한 변수만을 처리할 수 있다는 점이 문제입니다.
한 영역에서 다른 영역으로 이동하면 기존의 정제 결과물은 사라져 버립니다.
isString 구현에서 typeof를 이용해 매개변수 타입을 string으로 정제했지만 타입 정제는 새 영역으로 전달되지 않으므로 결과가 사라집니다.
결국 TypeScript가 알고 있는 사실은 isString이 boolean을 반환한다는 것뿐입니다.
따라서 타입 검사기에 isString이 boolean을 반환할 뿐 아니라 boolean이 true이면 isString에 전달한 인수가 string임을 알려야 합니다.
사용자 정의 타입 안전장치(user-defined type guard)란 기법으로 이를 해결할 수 있습니다.
function isString(a: unknown): a is string {
return typeof a === "string";
}
타입 안전장치는 TypeScript의 내장 기능으로 typeof와 instanceof로 타입을 정제할 수 있게 해 줍니다.
하지만 때론 자신만의 타입 안전장치가 필요한데 이때는 is 연산자를 사용합니다.
매개변수 타입을 정제하고 boolean을 반환하는 함수가 있다면 사용자 정의 타입 안전장치를 이용해 함수가 제대로 동작함을 보장하도록 만들 수 있습니다.
사용자 정의 타입 안전장치는 매개변수 하나에만 적용할 수 있지만 (유니온과 인터섹션 같은) 복합 타입에도 적용할 수 있습니다.
type LegacyDialog = // 블라 블라
type Dialog = // 블라 블라
function isLegacyDialog(
dialog: LegacyDialog | Dialog
): dialog is LegacyDialog {
// 블라 블라
}
사용자 정의 타입 안전장치를 자주 사용할 일은 없겠지만, 잘 활용하면 깨끗하고 재사용할 수 있는 코드를 구현할 수 있습니다.
사용자 정의 타입 안전장치를 사용하지 않으면 isLegacyDialog와 isString 같은 잘 캡슐화되고 가독성 좋은 함수를 활용하지 못하고, 대신 typeof나 instanceof 타입 안전장치를 코드에 일일이 추가해야 합니다.
'👶 TypeScript' 카테고리의 다른 글
조건부 타입 - 분배적 조건부 (0) | 2023.01.21 |
---|---|
조건부 타입 (0) | 2023.01.21 |
고급 함수 타입들 - 튜플의 타입 추론 개선 (0) | 2023.01.20 |
컴패니언 객체 패턴(companion object pattern) (0) | 2023.01.20 |
매핑된 타입(mapped type) (0) | 2023.01.20 |