타입스크립트에서 변수에 명시적인 타입을 지정하지 않을 때, 컴파일러가 변수의 타입을 결정하는 방식을 타입 넓히기라고 합니다.
let x = 'x';
위 코드에서 x는 타입스크립트에 의해 단순히 문자열 'x'로 한정되지 않고, string 타입으로 넓혀서 추론됩니다. 이는 타입스크립트가 변수가 가질 수 있는 모든 가능한 문자열 값을 포괄하려고 하기 때문입니다.
아래는 컴포넌트의 포지션을 가져오는 함수입니다.
type Position = {
x: number
y: number
z: number
}
function getPosition(position: Position, axis: 'x' | 'y' | 'z') {
return position[axis]
}
이 함수는 런타임에서 오류 없이 실행되지만, 편집기에서는 타입 에러가 발생할 수 있습니다. 예를 들어 아래의 코드의 상황에서는 에러가 발생합니다.
let x = 'x';
let position = {x: 50, y: 10, z: 200};
getPosition(position, x); // [error] x는 'x' | 'y' | 'z' 타입이 아닙니다.
이 오류는 x의 타입이 string으로 넓혀 추론되기 때문에 발생합니다. 이 문제를 해결하기 위해, x에 명시적으로 'x' | 'y' | 'z' 타입을 지정해야 합니다.
const를 이용해서 넓힐 수 있습니다.
let name = "zero" // name: string
const name = "one" // name: "one"
const
로 선언된 변수는 그 값이 변경되지 않으므로, 타입스크립트는 리터럴 타입을 유지합니다. 그러나 객체나 배열의 경우, 내부 값의 변경은 허용되므로 주의가 필요합니다.
const profile = {
name: 'zero',
};
function logName(name: 'zero') {
console.log(name);
}
logName(profile.name); // [error] 파라미터의 값으로 'zero' 리터럴 타입을 주세요.
이 경우에도 객체에 명시적인 타입을 지정해주는 것이 좋습니다.
type Profile = {
name: 'zero';
}
const profile: Profile = {
name: 'zero',
};
const 단언문을 사용하여 객체 전체의 타입 넓히기를 제어할 수 있습니다.
const person = {
name: "zero",
age: 20
}; // 타입은 { name: string, age: number }
const personConst = {
name: "zero" as const,
age: 20
}; // 타입은 { readonly name: "zero", age: number }
const personAsConst = {
name: "zero",
age: 20
} as const; // 타입은 { readonly name: "zero", readonly age: 20 }
위 예시처럼, as const를 사용하면 객체의 모든 프로퍼티를 리터럴 타입으로 고정시킬 수 있습니다. 이 방법은 특히 객체 내의 값이 변하지 않기를 원할 때 유용하게 사용할 수 있습니다.