타입스크립트를 더 유용하게 사용할 수 있는 방법에 대해 알아보자!
한 가지의 타입을 기본으로 해서 다른 종류의 타입으로 변환하는 것이 가능하다.
인터페이스: 규격사항.
어떤 특정한 규격을 정의해 구현해야 한다면 인터페이스를 쓰는 것이 더 정확하다.
누군가가 구현할 사람이 있는 경우
타입: 어떤 데이터를 담을 때 어떤 데이터를 담을 수 있을지 타입을 결정
구현할 목적이 아닌 데이터를 담을 목적으로 만든다면 타입을 쓰는 것이 더 적절하다.
type alias는 intersection을 사용해서 원하는 타입을 추가할 수 있고,
interface는 상속을 사용해서 추가할 수 있다.
type PositionType = {
x: number;
y: number;
};
interface PositionInterface {
x: number;
y: number;
}
interface ZPositionInterface extends PositionInterface {
z: number;
}
type ZPositionType = PositionType & { z: number };
이미 선언된 타입을 한번 더 선언해 합칠 수 있다.
type alias는 중복 선언이 되지 않는다.
type PositionType = {
x: number;
y: number;
};
interface PositionInterface {
x: number;
y: number;
}
interface PositionInterface {
z: number;
}
//x,y,z를 합쳐 사용할 수 있다.
type PositionType {
}
// error: Duplicate identifier 'PositionType'
type Person = {
name: string;
age: number;
};
type Name = Person['name']; // string
type NumberType = number;
type Direction = 'left' | 'right';
}
인덱스 타입은 다른 타입에 있는 키에 접근해서 그 키의 value의 타입을 그대로 선언할 수 있다.
const obj = {
name: 'ellie',
};
obj.name; // ellie
obj['name']; // ellie
type Animal = {
name: string;
age: number;
gender: 'male' | 'female';
};
type Name = Animal['name']; // string
const text: Name = 'hello';
type Gender = Animal['gender']; //'male' | 'female'
type Keys = keyof Animal; // 'name' | 'age' | 'gender'
//Animal에 있는 모든 key의 타입을 유니온타입으로 keys에 할당한다.
const key: Keys = 'gender';
//할당된 Animal의 키 중 한 가지만 할당이 가능하다.
type Person = {
name: string;
gender: Animal['gender'];
};
const person: Person = {
name: 'ellie',
gender: 'male',
};
type ReadOnly<T> = {
readonly [P in keyof T]: T[P];
};
const video: ReadOnly<Video> = {
title: 'hi',
author: 'ellie',
};
//아래와 같다.
// type VideoReadOnly = {
// readonly title: string;
// readonly author: string;
// };
type Check<T> = T extends string ? boolean : number;
//기존에 것이 상속하는 타입이 string이라면 불리언으로, 아니라면 number로 타입을 지정한다.
type Type = Check<string>; // boolean
type ToDo = {
title: string;
description: string;
};
function display1(todo: ToDo) {
// todo.title = 'jaja';
/**
* 그냥 ToDo 타입 오브젝트를 전달해주게 되면 다른 개발자가 임의로 title 등의 값을 변경할 수가 있다.
* 불변성을 보장하기 위해 readonly를 사용한다.
*/
}
function display2(todo: Readonly<ToDo>) {
// todo.title = 'jaja';
/**
* 이렇게만 적어도 Readonly라는 타입은 이미 내장되어있기 때문에 적용이 된다.
* 컨트롤을 누르고 클릭해보면 어떻게 구성되어있는지 볼 수 있는데, 유틸리티 타입으로 구성된 Readonly 타입은
* map 타입을 사용해 모든 값을 readonly로 변경시켜준다.
*/
}
partial이라는 유틸리티 타입은 기존의 타입을 유지하면서 특정 부분만 변경하고 싶을 때 사용한다.
type ToDo = {
title: string;
description: string;
label: string;
priority: 'high' | 'low';
};
function updateTodo(todo: ToDo, fieldsToUpdate: Partial<ToDo>): ToDo {
return { ...todo, ...fieldsToUpdate };
}
const todo: ToDo = {
title: 'learn TypeScript',
description: 'study hard',
label: 'study',
priority: 'high',
};
const updated = updateTodo(todo, { priority: 'low' });
console.log(updated);
type Video = {
id: string;
title: string;
url: string;
data: string;
};
type VideoMetadata = Pick<Video, 'id' | 'title'>;
//Video 타입 중 id 혹은 title만 사용하고 싶다.
function getVideo(id: string): Video {
return {
id,
title: 'video',
url: 'https://..',
data: 'byte-data..',
};
}
function getVideoMetadata(id: string): VideoMetadata {
return {
id: id,
title: 'title',
};
}
//pick 이라는 utility type은 기존에 있는 타입 중 원하는 타입만 골라서 사용할 수 있다.
Omit은 pick과 반대로 제외하고 싶은 타입만 명시해줄 수 있다.
type Video = {
id: string;
title: string;
url: string;
data: string;
};
type VideoMetadata = Omit<Video, 'url' | 'data'>;
function getVideo2(id: string): Video {
return {
id,
title: 'video',
url: 'https://..',
data: 'byte-data..',
};
}
function getVideoMetadata2(id: string): VideoMetadata {
return {
id: id,
title: 'title',
};
}
타입을 연결하고 싶을 때 키와 내용을 지정해준다.
type PageInfo = {
title: string;
};
type Page = 'home' | 'about' | 'contact';
const nav: Record<Page, PageInfo> = {
home: { title: 'Home' },
about: { title: 'About' },
contact: { title: 'Contact' },
};