상호 간에 정의한 약속 혹은 규칙
Interface
는 객체 지향 프로그래밍(Object-Oriented Programming)
에서 사용되는 개념으로 멤버에 대한 기본 구현을 정의할 수 있다.
Typescript
에서 Interface
는 보통 다음과 같은 범주에 대한 약속을 정의한다.
객체의 스펙(속성과 속성의 타입)
함수의 파라미터
함수의 스펙(파라미터, 반환 타입 등)
배열과 객체를 접근하는 방식
클래스
아래 logName
함수의 인자는 age
를 속성으로 갖는 객체이며, 인자를 받을 때 객체의 속성 타입까지 정의할 수 있다.
let fruits = { name: 'apple', price: 10 };
function logName(obj: { name: string }) {
console.log(obj.name); // apple
}
logAge(person); // apple
위의 코드를 Interface
로 변환하면 이제는 logName
함수의 인자가 더 명시적으로 변경된다.
즉, logName
함수의 인자는 FruitName
이라는 타입을 반드시 가져야한다.
interface FruitName {
name: string;
}
function logName(obj: FruitName) {
console.log(obj.name);
}
let fruit = { name: 'apple', price: 10 };
logAge(fruit);
위 Interface
코드를 확인해보면 다음과 같이 추론할 수 있다.
Interface
를 인자로 받아 사용할 때 항상 Interface
속성 갯수와 인자로 받는 객체의 속성 갯수를 일치시키지 않아도 된다.
즉, Interface
의 정의된 속성, 타입의 조건만 만족하면 객체의 속성 갯수가 더 많아도 상관 없다는 의미이다.
위에서 설명했듯 Interface
를 사용할 때 정의되어 있는 속성을 모두 사용하지 않아도 된다.
이를 옵션 속성이라고 하며, 속성 끝에 '?'
를 붙여 사용한다.
interface Person {
name: string;
age?: number;
}
let myName = {
name: 'Mirrer'
};
function logName(name: Person) {
console.log(beer.name); // Mirrer
}
logName(myName);
Rreadonly
, 읽기 전용 속성은 객체 생성 이후 값을 변경할 수 없는 속성을 의미한다.
읽기 전용 속성은 아래와 같이 readonly
키워드를 사용하며, Interface
로 객체를 선언한 뒤 수정하려고 하면 아래와 같이 오류가 발생한다.
interface Person {
readonly name: string;
}
let myName: Person = {
name: 'Mirrer'
};
myName.name = 'Change Mirrer'; // error!
배열을 선언할 때 ReadonlyArray<T>
타입을 사용하면 읽기 전용 배열을 생성할 수 있다.
let numbers: ReadonlyArray<number> = [1, 2, 3];
arr.push(4); // error
arr[0] = 10; // error
Typescript
는 Interface
를 이용하여 객체를 선언할 때 좀 더 자세한 속성 검사를 수행한다.
아래 코드를 확인해보면 Person
Interface
는 name
속성을 선언했다.
하지만 logName
함수는 인자로 넘기는 객체에 names
가 선언되어 있어 오탈자 점검을 요하는 오류가 발생한다.
interface Person {
name: string;
}
function logName(name: Person) {
// ..
}
logName({ names: 'Mirrer' }); // error: Object literal may only specify known properties, but 'names' does not exist in type 'Person'. Did you mean to write 'name'?
만약 이런 타입 추론을 무시하고 싶다면 아래와 같이 선언한다.
let myName = { names: 'Mirrer' };
logName(myName as Person);
반대로 Interface
에 정의하지 않은 속성들을 추가로 사용하고 싶다면 아래와 같은 방법을 사용한다.
interface Person {
name?: string;
[propName: string]: any;
}
Interface
는 함수의 타입을 정의할 때에도 사용할 수 있으며, 함수의 인자의 타입과 반환 값의 타입을 지정한다.
interface WishList {
(name: string, count: number): boolean;
}
let addItem: WishList;
addItem = function(name: string, count: number) {
console.log(`${name}상품 ${count}개 구매했습니다.`);
return true;
}
Typescript
는 C#
, Java
...등의 객체 지향 언어처럼 Class
가 특정 조건을 만족하는 타입 규칙을 지정할 수 있다.
interface Name {
productName: string;
}
class Price implements Name {
productName: string = 'apple';
logName(name: string) {
this.productName = name;
}
constructor() {}
}
Interface
또한 Class
와 마찬가지로 확장이 가능하며, 여러 부모 Interface
를 상속받을 수도 있다.
interface Apple {
name: string;
}
interface Banana {
color: string;
}
interface Orange extends Apple {
price: number;
}
let fruit = {} as Orange;
fruit.name = 'apple';
fruit.color = 'yellow';
fruit.price = 100;
TypeScript: JavaScript With Syntax For Types.
React TypeScript Tutorial for Beginners - Codevolution
타입스크립트 입문 - 기초부터 실전까지 - 장기효