인터페이스는 약속 또는 규칙을 의미한다. 사용하는 코드에 대해서 여러 규칙들을 정의할 수 있는데, 이를 인터페이스라고 한다.

밑의 코드를 보자. printLabel이라는 함수는 labeledObj라는 객체를 받는다. 이 때 해당 객체 안의 string 타입의 label이라는 속성을 가져야 한다.

function printlabel(labelObj: {label: string}) {
    console.log(labelObj.label)
}

let myObj = {size: 10, label: 'Size 10 Object'}
printlabel(myObj)  // 'Size 10 Object'

이를 string 타입의 label 속성을 가진 인터페이스로 재작성 할 수 있다.

**interface LabeledValue** {
    label: string;
}

function printlabel(labelObj: **LabeledValue**) {
    console.log(labelObj.label)
}

let myObj = {size: 10, label: 'Size 10 Object'}
printlabel(myObj)

첫 번째 코드와 다른 것은 없지만, 인터페이스 안에 객체의 속성들에 대한 요구 조건을 넣어둠으로써 재사용성이 가능해진다.

옵션 속성

인터페이스 안에 정의되어 있는 속성이 100% 다 일치해야 하는 것은 아니다. 선택적으로 속성을 사용할 수도 있다. 이를 옵션 속성이라 한다.

interface CraftBeer {
    name: string;
    hop?: number;
}

let myBeer = {
    name: 'Saporo'
}

function brewBeer(beer: CraftBeer) {
    console.log(beer.name)
}

brewBeer(myBeer)

위 코드에서 myBeer라는 객체 안에 hop이라는 속성이 존재하지 않아도 괜찮다. CreaftBeer 인터페이스에서 hop을 옵션 속성으로 주었기 때문이다.

하지만 아래와 같이 선언되어져 있는 속성에 잘못된 타입을 선택했거나

interface CraftBeer {
    name: string;
    **hop?: number;**
}

let myBeer = {
    name: 'Saporo',
    **hop: 'jasmin'**
}

function brewBeer(beer: CraftBeer) {
    console.log(beer.name) // Error: Types of property 'hop' are incompatible.
}

brewBeer(myBeer)

인터페이스 내에 존재하는 속성이 아닌 경우

interface CraftBeer {
    name: string;
    hop?: number;
}

let myBeer = {
    name: 'Saporo',
}

function brewBeer(beer: CraftBeer) {
    console.log(beer.sample) // Error: Property 'sample' does not exist on type 'CraftBeer'.
}

brewBeer(myBeer)

혹은 오탈자가 발생한 경우

interface LabeledValue {
    label: string;
}

function printlabel(labelObj: LabeledValue) {
    console.log(labelObj.lavel)  // Error: Property 'lavel' does not exist on type 'LabeledValue'. Did you mean 'label'?
}

let myObj = {size: 10, label: 'Size 10 Object'}
printlabel(myObj)

에러를 발생시키게 된다.

따라서 인터페이스 내에 존재하지 않는 속성에 접근하거나 오탈자가 발생했을 때 그 문제를 지적해 줄 수 있다는 것이 옵션 속성의 장점이다(근데 존재하지 않는 속성에 대해서는 옵션 속성을 사용하지 않아도 작동하는 거 같기도..)