신선도 (Freshness)
- 구조적으로 타입 호환성이 있는 객체 리터럴 타입 검사를 쉽게 할 수 있도록, 신선도라는 개념을 제공한다.
- (엄격한 객체 리터럴 검사라고도 함)
예를들어.. 에러가 안나는 케이스는 아래와 같다.
function logName(something: { name: string }) {
console.log(something.name);
}
var person = { name: 'matt', job: 'being awesome' };
var animal = { name: 'cow', diet: 'vegan, but has milk of own species' };
var random = { note: `I don't have a name property` };
logName(person); // 오케이
logName(animal); // 오케이
logName(random); // 오류: 속성 `name` 누락
다만 아래와 같이 객체 리터럴을 넣을 경우 에러 남
function logName(something: { name: string }) {
console.log(something.name);
}
logName({ name: 'matt' }); // 오케이
logName({ name: 'matt', job: 'being awesome' }); // 오류: 객체 리터럴은 정의된 속성만 지정해야 함. 여기서 `job`은 불필요.
왜 객체 리터럴일 때만 이런 타입 검사가 진행되나?
- 속성이 추가로 입력되었으나, 그 속성이 실제로 사용되지 않는다면, 대부분 오타이거나 API를 잘못 이해한 케이스이기 때문!
사용 사례 - React State
- 컴포넌트에서 setState 호출 시, 일부 속성만 넣는경우가 흔하다.
// 아래와 같을 때
interface State {
foo: string;
bar: string;
}
// 하려고 한 것:
this.setState({foo: "Hello"}); // 오류: 속성 bar 누락
// State에 `foo`와 `bar` 둘 다 있기 때문에 TypeScript에서는 이렇게 할 수 밖에 없음:
this.setState({foo: "Hello", bar: this.state.bar});
그래도 열어두고 싶다면?
- 인덱스 시그니쳐 사용해서 열어두면 된다.
type Food = {
protein: number;
carbohydrates: number;
fat: number;
[x: string]: any /** index signature */
}
반대로 모든 경우에 타입 호환이 되지 않도록 하고싶다면? Branded Type을 사용한다.