타입 검사는 값의 형태에 초점을 맞추고 있다. 이를 '덕 타이핑(duck typing)' 혹은 '구조적 서브타이핑(structural subtyping)'이라 한다.
인터페이스는 이런 타입들의 이름을 짓는 역할, 코드 안의 계약을 정의, 프로젝트 외부에서 사용하는 코드의 계약을 정의한다.
인터페이스가 동작하는지 확인하는 방법을 알아보자.
function printLabel(labeleObj: { label: string}) {
console.log(labeledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
타입 검사는 printLabel
호출을 확인한다.
printLabel
함수는 String 타입의 label
을 갖는 객체를 1개의 매개변수로 가진다.
이 객체는 실제로 더 많은 프로퍼티를 가지고 있지만, 컴파일러는 다음의 2가지만 검사한다.
이번에는 같은 예제를 문자열 타입의 프로퍼티 label
을 가진 인터페이스로 작성해보자.
interface LabeledValue {
label: string;
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label);
}
let myObj = {size: 10, label:"Size 10 Object"};
printLabel(myObj);
LabeledValue
인터페이스는 이전 예제의 요구사항을 똑같이 기술하는 이름으로 쓸 수 있다. 이 인터페이스는 여전히 문자열 타입의 label
프로퍼티 하나를 가짐을 의미한다. 다른 언어처럼 printLabel에 전달한 객체가 이 인터페이스를 구현해야 한다고 명시적으로 얘기할 필요는 없다. 함수에 전달된 객체가 나열된 요구 조건을 충전하면 허용된다.
타입 검사는 프로퍼티들의 순서를 요구하지 X.
단지 인터페이스가 요구하는 프로퍼티들이 존재하는지, 프로퍼티들이 요구하는 타입을 가졌는지만 확인한다.
인터페이스의 모든 프로퍼티가 필요한 것은 아니다. 특정 조건에서만 존재하거나, 아예 없을 수 있다.
선택적 프로퍼티들은 객체 안의 몇 개의 프로퍼티만 채워 함수에 전달하는 "option bags"같은 패턴을 만들 때 유용하다.
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): {color: string; area: number} {
let newSquare = {color: "white", area: 100};
if(config.color) {
// if(confing.clor) { 로 프로퍼티의 이름을 잘못 입력하면 Error를 띄움
newSquare.color = config.color;
}
if(config.width) {
newSquare.area = config.width * config.width; // 넓이
}
return newSquare;
}
let mySquare = createSquare({color: "black"});
선택적 프로퍼티를 가지는 인터페이스는 다른 인터페이스와 비슷하게 작성되고, 선택적 프로퍼티는 선언에서 프로퍼티 이름 끝에 ?
를 붙인다.
선택적 프로퍼티의 이점
- 인터페이스에 속하지 않는 프로퍼티의 사용을 방지함
- 가능한 속성을 기술함
객체가 처음 생성될 때만 수정가능해야하는 프로퍼티들도 있다. 이러한 경우 프로퍼티 앞에 readonly
를 넣으면 된다.
interface Point {
readonly x: number;
readonly y: number;