ReadonlyArray(const assertions로 생성한 배열)은 각 요소들이 불변하기때문에 그 자체로 타입이 된다.
const colors = ['Slifer Red', 'Ra Yellow', 'Obelisk Blue'] as const;
// 추론되는 타입: readonly ["Slifer Red", "Ra Yellow", "Obelisk Blue"]
type ColorType = typeof colors[number]; // "Slifer Red" | "Ra Yellow" | "Obelisk Blue"
function validateColor(color: ColorType): void {
// do something
}
위와 같은 방식으로, 상수와 타입을 만드는 패턴을 쓰거나 본 적이 있을 것이다.
그런데 아래와 같은 상황일 때 타입 오류 문제가 발생할 수 있다:
const userInput: string = getUserInput();
function validateColor(color: ColorType): void {
return colors.includes(userInput); // 타입 에러 !!
}
Argument of type 'string' is not assignable to parameter of type '"Slifer Red" | "Ra Yellow" | "Obelisk Blue"'. ts(2345)
추론된 타입 상 colors
의 요소는 Slifer Red
, Ra Yellow
, Obelisk Blue
중에 하나이다. 따라서 string
타입인 userInput
과 비교할 수 없는 것이다.
그렇다면, 아래와 같이 colors와 같은 값을 가지면서 string
타입인 배열을 새로 만들고, includes
를 쓰면 문제가 해결될 것이다.
const userInput: string = getUserInput();
const stringColors: string[] = [...colors];
stringColors.includes(userInput); // 정상 !!
하지만 이 해결방법은 다른 문제점을 일으킨다:
const userInput: string = getUserInput();
const stringColors: string[] = [...colors];
function doSomethingWithColor(color: ColorType): void {
// do something
}
if (stringColors.includes(userInput)) {
doSomethingWithColor(userInput); // 타입 에러 !!
}
Argument of type 'string' is not assignable to parameter of type '"red" | "green" | "blue"'.ts(2345)
inlcudes
를 통과하더라도, userInput
은 여전히 string
으로 추론된다. stringColors
의 타입이 string[]
이기 때문에 타입이 좁혀지지 않는 것이다.
타입 서술어 (type predicates)를 사용하면 된다.
boolean을 반환하는 함수에서 사용할 수 있는데, 함수의 파라미터의 타입을 좁혀준다.
export function contains<T extends string>(
list: ReadonlyArray<T>,
value: string,
): value is T {
return list.some((item) => item === value);
}
위 함수가 true
를 반환하면, 타입 체커가 value
파라미터를 T
타입으로 추론한다는 의미이다.
T
는 generic이기 때문에 contains(colors, userInput)
실행 컨텍스트에서는 ColorType
로 추론된다.
const userInput: string = getUserInput();
if (contains(colors, userInput)) {
doSomethingWithColor(userInput); // 정상 !! if 문을 통과하면서 userInput이 ColorType 추론된다.
}
타입 서술어로 타입을 넓힐 수는 없다. 그런 상황일 땐 별 수 없이 타입 단언문 as
를 써야만 한다.