최종 수정 : 2024-05-27
cf. 리터럴 타입
변수의 값을 타입으로 정의하는 것이며, let을 사용하느냐 const를 사용하느냐에 따라 타입이 다르게 추론된다.
// let은 타입추론, const는 리터럴 타입
let literal1 = '타입스크립트 공부';
const literal2 = '타입스크립 익히기';
let medium = 90;
const large = 100;
타입 별칭(type alias)
타입에 '이름'을 정하는 문법이다. 복잡한 타입에 이름을 붙이고 재사용하고 싶을 때 사용한다.
- 특정 타입이나 인터페이스 등을 참조할 수 있는 타입 변수를 의미
- 가장 큰 장점 : 반복되는 타입 코드를 줄여 준다.
타입 별칭과 인터페이스의 차이
1) 코드 에디터에서 표기 방식 차이
- 타입 별칭은 타입 정보가 나타난다.
2) 사용할 수 있는 타입의 차이
- 인터페이스 : 주로 객체의 타입을 정의
- 타입 별칭 : 일반 타입에 이름을 짓는 데 사용하거나 유니언 타입, 인터섹션 타입 등에도 사용 / 제네릭이나 유틸리티 타입 등에서도 사용할 수 있다.
type BookTitle = string;
type BookInfo = Book | Page; // 유니언 타입
type BookInfo = Book & Page; // 인터섹션 타입
인터페이스와 타입 별칭의 정의를 함께 사용할 수도 있다.
interface BookInfo {
name: string;
page: number;
}
type BookPublish {
state: boolean;
}
type BookState = BookInfo & BookPublish;
3) 타입 확장 관점에서 차이
타입 확장 : 이미 정의되어 있는 타입들을 조합하여 더 큰 의미의 타입을 만드는 것
- 인터페이스 : 상속
- 타입 별칭 : 인터섹션
=> 유연하게 타입을 확장하는 관점에서는 타입 별칭보다 인터페이스가 더 유리하다.
인덱스 시그니처(index signature)
- 정확히 속성 이름을 명시하지 않고 속성 이름의 타입과 속성 값의 타입을 정의하는 문법
- 단순히 객체와 배열을 인덱싱할 때 활용될 뿐만 아니라 객체의 속성 타입을 유연하게 정의할 때도 사용된다.
- 속성 이름과 속성 값이 정의된 것에 부합한 정보면 1개든 n개든 모두 추가할 수 있다는 장점이 있다.
interface BookList {
[name: string]: string;
}
// ex)
type CountryCodes = {
[Key: string]: string;
};
let countryCodes: CounteryCodes = {
Korea: "ko",
UnitedState: "us",
UnitedKingdom: "uk",
};
인덱스 시그니처가 적용되어 있는 경우에는 구체적으로 어떤 속성이 제공될지 알 수 없어 코드 자동 완성이 되지 않는다.
interface Book {
[property: string]: string
athor: string; // 반드시 있어야 한다.
page: number; // 반드시 있어야 한다.
}
let typescript: Book = {
athor: 'teadyeong',
page: 769
subtitle: 'extend js', // 인덱스 시그니처에 의한 추가
publisher: 'A' // 인덱스 시그니처에 의한 추가
}
객체의 속성 이름과 속성 값이 정해져 있는 경우
-> 속성 이름과 속성 값 타입을 명시해서 정의하고
속성 이름은 모르지만 속성 이름의 타입과 값의 타입을 아는 경우
-> 인덱스 시그니처를 활용
Enum과 타입 별칭
// Enum을 사용 (권장)
enum UserType {
Admin = 'admin',
User = 'user',
Guest = 'guest',
}
const role = UserType.Admin;
console.log(role === UserType.Guest); // false
// 타입 별칭과 Union을 사용
type UserType = 'admin' | 'user' | 'guest'
const role: UserType = 'admin';
console.log(role === 'guest');
둘의 차이는 JavaScript로 트랜스파일링 했을 때, 드러난다.
1) Enum은 별도의 자바스크립트 객체를 생성하고, 그 객체를 사용한다.
"use strict";
var UserType;
(function (UserType) {
UserType["Admin"] = "admin";
UserType["User"] = "user";
UserType["Guest"] = "guest";
})(UserType || (UserType = {}));
const role = UserType.Admin;
console.log(role === UserType.Guest);
2) 반면 타입 별칭은 타입스크립트에서만 의미 있는 코드이므로, 트랜스파일 했을 때 추가로 객체를 생성하지 않고 값만 사용하는 코드가 만들어진다.
"use strict";
const role = 'admin';
console.log(ole === 'guest');
대부분의 경우 Enum 또는 타입 별칭을 모두 사용할 수 있으나, Enum의 목적에 맞는 경우라면 Enum 문법을 사용하는 것이 좋다.
선언 병합(declaration merging)
- 인터페이스는 동일한 이름으로 인터페이스를 선언하면 내용을 합치는 특성이 있다.
interface Book {
name: string;
page: number;
}
interface Book {
athor: string;
}
// =>
interface Book {
name: string;
page: number;
athor: string;
}
타입 별칭은 언제 쓰는 것이 좋은가?
1) 타입 별칭으로만 정의할 수 있는 타입들
- 주요 데이터 / 유니언 / 인터섹션 / 제네릭 / 유틸리티 / 맵드
- 제네릭은 인터페이스와 타입 별칭에 모두 사용할 수 있다.
- 유틸리티 타입이나 맵드 타입은 기존에 정의된 타입을 변경하거나 일부만 활용할 때 사용한다.
type MyBook = string; // 주요 데이터 타입
type BookInfo = string | number; // 유니언 타입
type BookInfo = Book & BookPage; // 인터섹션 타입
// 제네릭
type BookInfo<T> = {
name: string;
title: T;
}
// 유틸리티 타입
type Book = { name: string; page: number; author: string; }
type BookSelected = Pick<Book, 'name'>
// 맵드 타입
type Selector<T, K extends keyof T> = {
[P in K]: T[P];
}
2) 백엔드와의 인터페이스 정의
영역 간 접점(데이터)을 서로 맞추는 작업
인터페이스로도 가능하다. 타입 확장 측면에서, 타입 별칭이 제공하는 미리보기 효과보다 인터페이스로 작업하는 게 더 이점이 크다.
// 1. 타입 별칭으로 API 함수의 응답 형태를 정의
type Book = {
name: string;
page: number;
}
function fetchData(): Book {
return axios.get('http://localhost:3000/books/1');
}
// 2. 인터페이스로 API 함수의 응답 형태를 정의
interface Book {
name: string;
page: number;
}
function fetchData(): Book {
return axios.get('http://localhost:3000/books/1');
}
'프론트엔드 > TS 공부' 카테고리의 다른 글
제네릭 / 제네릭 타입 / 제네릭 인터페이스와 제네릭 타입 별칭 (0) | 2023.08.22 |
---|---|
이넘(enum) (0) | 2023.07.26 |
리터럴 타입(literal type) / 유니언 타입(union type) / 인터섹션 타입(intersection type) (0) | 2023.07.26 |
인터페이스(Interface) (0) | 2023.07.26 |
변수와 함수의 타입 정의 (0) | 2023.07.25 |
댓글