[TypeScript] 타입스크립트 인터페이스(interface)와 타입 별칭 (alias)
글 작성자: 망고좋아
반응형
🎯 인터페이스와 타입 별칭
- 타입스크립트에서 타입을 기술하는 2가지 방법이 있다. ⇒ 인터페이스, 타입 별칭(타입 알리아스)
- 타입 별칭은 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수를 의미한다.
- 인터페이스는 상호 간에 정의한 약속 혹은 규칙을 의미한다.
📝 타입 별칭 (Type Aliases)
// string 타입을 사용할 때
const name: string = 'capt';
// 타입 별칭을 사용할 때
type MyName = string;
const name: MyName = 'capt';
// Ex
type Name = string;
type Email= string;
type FooFunction = () => string; // 함수도 타입을 가지고 규정할 수 있다. 반환값이 string
- 타입 별칭은 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수를 의미한다.
- 변수명에 의미를 부여할 수 있지만 string 타입에 의미를 부여하고 싶을 때 타입 별명(타입 별칭, 타입 알리아스)을 사용한다.
- 타입 별칭은 새로운 타입 값을 하나 생성하는 것이 아니라 정의한 타입에 대해 나중에 쉽게 참고할 수 있게 이름을 부여하는 것과 같다.
- 타입 별칭은 첫 글자를 대문자로 쓰는 컨벤션을 따름
type Developer = {
name: string;
skill: string;
}
interface
레벨의 복잡한 타입에도 별칭을 부여할 수 있다.
type User<T> = {
name: T
}
- 타입 별칭에 제네릭도 사용할 수 있다.
type YesOrNo = 'Y' | 'N';
type DayOfWeek = '월' | '화' | '수' | '목' | '금' | '토' | '일';
- 위 두 개는 문자열로만 제한하는 유니언 타입을 가지고 있다.
- 타입으로 기술된 것은 컴파일 타임에 이 값이 들어가는지 안 들어가는지, 그런 코드가 있는 확인하는 용도로 사용된다.
enum DayOfTheWeek = {'월', '화', '수', '목', '금', '토', '일'};
- 반면 enum은 실제 데이터다. 컴파일 타임이 아닌 런타임에 실제로 월화수목금..이 들어간다.
- enum은 특정 값으로 제한하는 기능은 유사하지만 실제 데이터고, 타입 알리아스는 컴파일 타임에 타입만 검사하는 용도로 사용된다는 차이점이 있다.
📕 여러 개의 타입 별칭을 하나로 합치기 :: intersection
type TUserProfile = IUser & {
profileImage: string;
github?: string;
twitter?: string;
}
- IUser를 상속받아서 intersection(&) 교차시킬 거다! merge 되는 것과 똑같은 효과를 가진다.
- IUser 자리에 타입 알리아스가 오든 interface가 오든 상관하지 않는다.
📝 인터페이스(interface)
interface IUser {
readonly id: number;
readonly name: Name;
email: string;
receiveInfo: boolean;
active: YesOrNo;
}
- 인터페이스는 상호 간에 정의한 약속 혹은 규칙을 의미한다.
- 인터페이스와 타입 알리아스를 섞어 사용할 수 있다.
- IUser라는 객체 데이터를 만들면 저런 규격으로 만들어야 해!라는 것을 의미한다.
// logAge() 함수에서 받는 인자의 형태는 age를 속성으로 갖는 객체
let person = { name: 'Capt', age: 28 };
function logAge(obj: { age: number }) {
console.log(obj.age); // 28
}
logAge(person); // 28
// 인터페이스로 변환
interface personAge {
age: number;
}
function logAge(obj: personAge) {
console.log(obj.age);
}
let person = { name: 'Capt', age: 28 };
logAge(person);
logAge()
의 인자는personAge
라는 타입을 가져야 한다.- 인터페이스를 인자로 받아 사용할 때 항상 인터페이스의 속성 개수와 인자로 받는 객체의 속성 개수를 일치시키지 않아도 된다.
- 즉, 인터페이스에 정의된 속성, 타입의 조건만 만족한다면 객체의 속성 개수가 더 많아도 상관없다.
- 또한, 인터페이스에 선언된 속성 순서를 지키지 않아도 된다.
🛠 예시 코드
import * as allTypes from './type';
const iUser: allTypes.IUser = {
id:1,
name: '빌 게이츠',
email: 'bill@ms.com',
receiveInfo: false;
active: 'Y';
}
const foo: allTypes.FooFunction = function() {
return 'test';
}
- 객체 사용하듯이 사용한다.
import *
을 사용하면 뒤에 별칭을 붙여줘야 된다.- 가지고 올 요소들이 많으면 개별로 매번
import
해주는 것보다*
를 사용하는 게 편리할 수 있다.
📕 옵셔녈(?)과 읽기 전용 속성(readonly)
export interface IUser {
readonly id: number;
readonly name: Name;
email: string;
receiveInfo: boolean;
active: YesOrNo;
}
export interface IUser {
address?: string;
}
// 인터페이스는 이름이 중복되면 아래처럼 이러한 효과를 낸다.
// 하나인데 2개로 나뉘어 놨구나~ 라고 인지한다.
// 하지만 이렇게 나눠서 사용하는 것은 비추천한다. -> 알아보기 힘들다.
// => 하나에 몰아서 넣자!
export interface IUser {
readonly id: number;
readonly name: Name;
email: string;
receiveInfo: boolean;
active: YesOrNo;
address?: string;
}
- ? 는 옵셔널을 뜻한다.
- 객체를 만드는데 객체의 address의 속성은 있어도 되고 없어도 된다.
- 읽기 전용 속성은 인터페이스로 객체를 처음 생성할 때만 값을 할당하고 그 이후에는 변경할 수 없는 속성을 의미한다.
readonly
키워드를 속성을 앞에 붙인다.
📕 여러 개의 인터페이스를 하나로 합치기
export interface IUserProfile extends IUser {
profileImage: string;
github?: string;
twitter?: string;
}
- 상속과 유사한 느낌이다.
- IUser속성이 반복되어서 사용된다면 클래스의 상속과 유사하게 extends 키워드를 사용해서 인터페이스를 확장할 수 있다. → IUser를 재활용할 수 있는 문법 요소이다.
- extends 뒤에 interface가 아닌 타입 알리아스가 와도 상관없다.
export interface Color {
fontColor: string;
strokeColor: string;
borderColor: string;
backgroundColor: string;
}
export type Display = {
display: 'none' | 'block';
visiblity: boolean;
opacity: number;
}
export type Geometry = {
width: number;
height: number;
padding: number;
margin: number;
}
//-----------------------------------
export interface IStyle extends Color, Display, Geometry {
tagName: string;
}
export type TStyle = Color & Display & Geometry & {
tagName: string;
}
📕 함수에 사용하기
// 함수도 가능
interface IGetApi {
(url: string. search?: string): Promise<string>; // : 뒤는 함수의 return값, ()안은 url과 search인자를 받는 함수
}
- 함수의 규격 정의할 때는 화살표 함수를 못 쓴다.
- 이렇게 함수 규격을 함수에 적용할 때는 함수 정의문이 아닌 함수 표현식을 사용해야 된다.
const getApi: allTypes.IGetApi = (url, search = '') => {
return new Pomise(resolve => recolve('OK'));
};
- 타입을 지정하기 위해서는 함수 표현식을 사용해야 된다.
코드
interface login {
(username: string, password: string): boolean;
}
let loginUser: login;
loginUser = function(id: string, pw: string) {
console.log('로그인 했습니다');
return true;
}
📕 클래스에 사용하기
export interface IRect {
id: number;
x: number;
y: number;
width: number;
height: number;
}
export interface IRectConstructor {
// 생성자로 호출할 때 생성자의 스펙은 이렇게 돼! 라고 인터페이스로 묘사
new (x: number, y: number, width: number, height: number) : IRect; // 반환값으로 IRect 즉, 이 클레스의 인터페이스라고 하는 형식
}
class Rect implements allTypes.IRect {
private id: number; // * private로 바꿔주는건 불가능하다. only public
x: number;
y: number;
width: number;
height: number;
constructor(x: number, y: number, width: number, height: number) {
this.id = Math.random() * 100000;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
function createDefaultRect(cstor: allTypes.IRect) {
return new cstor(0, 0, 100, 20); //클래스의 생성자를 호출할 때 생성자 인터페이스 필요
}
const rect1 = new Rect(0, 0, 100, 20);
const rect2 = createDefaultRect(Rect);
- interface는 항상 public, 공개된 속성만 기술한다.
- 클래스 같은 경우 인스턴스를 만들기 위해서 생성자가 호출된다. → 클래스의 규격과 생성자가 만들어내는 인스턴스의 규격이 미묘하게 다를 수 있다.
- 그래서 인터페이스를 이용해서 생성자의 규격을 기술할 수 있다.
📝 type vs interface
export interface IUser {
readonly id: number;
readonly name: Name;
email: string;
receiveInfo: boolean;
active: YesOrNo;
}
export type TUser = {
readonly id: number;
readonly name: Name;
email: string;
receiveInfo: boolean;
active: YesOrNo;
}
- 타입 별칭과 인터페이스의 가장 큰 차이점은 타입의 확장 가능 / 불가능 여부이다.
- 인터페이스는 확장이 가능한데 반해 타입 별칭은 확장이 불가능하다.
- 데이터를 표현할 때는 타입 알리아스 사용
- 데이터를 포괄하는 객체를 묘사하는 경우에는 인터페이스를 사용(메소드와 같이 구체적인 행위까지 포함된 객체를 디자인할 때)
- 클래스를 묘사할 때는 클래스 자체가 데이터와 행위를 포괄하고 있기 때문에 인터페이스를 사용하는 것이 훨씬 자연스럽다.
📌 참고
반응형
'프로그래밍 > TypeScript' 카테고리의 다른 글
[TypeScript] 타입스크립트 Getter & Setter / readonly / static (0) | 2021.11.24 |
---|---|
[TypeScript] 타입스크립트 Class 접근 제어자 (0) | 2021.11.24 |
[TypeScript] 타입스크립트 클래스 사용하기 - 상속, 추상 클래스, 추상 클래스를 활용한 디자인 패턴(Template Method Pattern) (0) | 2021.11.24 |
[TypeScript] 타입스크립트 함수 사용하기 (0) | 2021.11.24 |
[TypeScript] 타입스크립트 12개 타입 (0) | 2021.11.23 |
댓글
이 글 공유하기
다른 글
-
[TypeScript] 타입스크립트 Class 접근 제어자
[TypeScript] 타입스크립트 Class 접근 제어자
2021.11.24 -
[TypeScript] 타입스크립트 클래스 사용하기 - 상속, 추상 클래스, 추상 클래스를 활용한 디자인 패턴(Template Method Pattern)
[TypeScript] 타입스크립트 클래스 사용하기 - 상속, 추상 클래스, 추상 클래스를 활용한 디자인 패턴(Template Method Pattern)
2021.11.24 -
[TypeScript] 타입스크립트 함수 사용하기
[TypeScript] 타입스크립트 함수 사용하기
2021.11.24 -
[TypeScript] 타입스크립트 12개 타입
[TypeScript] 타입스크립트 12개 타입
2021.11.23