이 글은 타입스크립트 입문 - 기초부터 실전까지의 인터페이스와 타입 별칭을 보고 정리한 글입니다.
앞서 첫 번째 프로젝트 - 할 일 관리 애플리케이션을 진행하면서 interface에 대한 개념을 보았다.
타입 별칭 버전
type Todo = {
id: number,
title: string,
done: boolean
}
인터페이스 버전
interface Todo {
id: number;
title: string;
done: boolean;
}
다음과 같이 정의하고, 인터페이스가 없다면
{id: number; title: string; done: boolean}
과 같이 길고 중복되는 것을 타입으로 적어주어야 한다. 이를 간단하게 하기 위해 위와 같은Todo
라는 인터페이스를 사용한다.
interface User {
age: number;
name: string;
}
let jeongmin: User = {
age: 25,
name: '정민',
};
인터페이스 형식은 위와 같다.
User
라는 인터페이스가 정의되어 있다면 상호간의 약속했던 규칙에 따라User
형식대로 작성해주어야 한다.
// 함수에 인터페이스 활용
const getUser = (user: User) => {
console.log(user);
};
const capt = {
name: '캡틴',
};
getUser(capt)
함수에 아까 정의 해둔 User라는 인터페이스를 다음과 같이 사용하면 에러가 발생한다.
이 에러는 getUser함수 호출 시 전달되는 capt라는 인수가 User 인터페이스 형식에 맞지 않아서 발생하는 에러로 age
키와 값을 설정해주어야 한다.
// 함수에 인터페이스 활용
const getUser = (user: User) => {
console.log(user);
};
const capt = {
name: '캡틴',
age: 100,
};
getUser(capt);
이러한 구조가 타입스크립트에서 가장많이 볼 수 있는 인터페이스 활용 구조이다.
인터페이스를 다음과 같이 함수 구조를 정의하는 방식으로 사용할 수 있다.
// 함수의 스펙(구조)에 인터페이스를 활용
interface SumFunction {
(a: number, b: number): number;
}
let sum: SumFunction;
sum = function (c: number, d: number) {
return c + d;
};
이와 같이 사용하게 되면 sum이라는 변수에는 funcntion을 할당할 때, 인수 두개가 number타입이어야 하며, 반환값도 number타입이어야 한다. 만약 아무것도 반환하지 않는 함수를 sum에 할당 시, 다음과 같은 에러를 볼 수 있다.
// 인덱싱
interface StringArray {
[index: number]: string;
}
let arr: StringArray = ['a', 'b', 'c'];
// 에러 발생 코드
arr[0] = 10; // 'a'
배열의 인덱싱 방식또한 인터페이스로 정의할 수 있다.
위 코드는 에러가 발생하는데, arr이라는 배열에 0번 인덱스로 접근하여 10을 할당하려고 하기 때문에 string타입을 인덱싱 방식으로 인터페이스로 정의해 두어 에러가 발생한다.
// 딕셔너리 패턴
interface StringRegexpDictionary {
[key: string]: RegExp;
}
let obj: StringRegexpDictionary = {
sth: /abc/,
cssFile: /\.css$/,
jssFile: /\.js$/,
};
// obj['cssFile'] = 'a' // 에러 감지
Object.keys(obj).forEach(value => {});
딕셔너리 패턴으로 다음과 같이 사용할 수 있다. 또한 이렇게 작성하게 되면
Object.keys(obj).forEach(value => {});
이 부분에서 value의 타입이string
속성이라는 것을 타입추론에 의해 알려주는 것을 볼 수 있다.
// 인터페이스 확장
interface Person {
name: string;
age: number;
}
interface Developer extends Person {
language: string;
}
let captain: Developer = {
language: 'ts',
age: 100,
name: '캡틴',
};
OOP처럼 확장하여 인터페이스를 사용할 수 있다.
Developer라는 인터페이스에 Person을 확장하게 되면name, age, language
를 모두 작성해야 에러가 발생하지 않는다.
타입 별칭은 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수를 의미한다.
// number 타입 사용 시
const num: number = 123;
// 타입 별칭 사용 시
type MyNum = number;
const num2: MyNum = 123;
interface Person {
name: string;
age: number;
}
type Person2 = {
name: string;
age: number;
};
let jm: Person = {
name: '정민',
age: 25,
};
let jm2: Person2 = {
name: '정민',
age: 25,
};
다음과 같은 코드가 있다고 하였을 시,
jm:
옆의 인터페이스, 타입에 마우스를 갖다 대보면 아래의 결과를 확인할 수 있다.
인터페이스의 경우 그 안의 정보까지 보여주지는 않지만 타입의 경우 그 타입의 정보가 무엇인지 구체적으로 보여준다.
타입은 확장 불가능, 인터페이스는 확장 가능
--> 가능한 한 interface 사용하는 것이 확장가능성 측면에서 더 좋다!
참고: https://joshua1988.github.io/ts/guide/type-alias.html#type-vs-interface