※ 이 글은 이정한 강사님의 '한 입 크기로 베어먹는 타입스크립트'를 수강한 뒤 정리한 글입니다.
타입 조작이란?
- 원래 존재하던 타입들을 상황에 따라 유동적으로 다른 타입으로 변환하는 기능.
- 제네릭을 포함하여 총 7가지 존재.
1. 인덱스드 엑세스 타입
- 인덱스를 사용해 다른 타입내의 특정 프로퍼티 타입을 추출하는 타입.
- 객체, 배열, 튜플에 사용 가능.
- 인덱스 중첩 사용 가능.
※ 객체 프로퍼티 타입 추출
interface Post{
title: string;
content: string:
author: {
id: number;
name: string;
}
}
const post:Post = {
title: "게시글 제목",
content: "게시글 본문",
author: {
id: 1,
name: "이정환"
}
}
// 작성자 정보를 추출하는 함수
function printAuthorInfo(author: {id: number; name: string}){
console.log(`${author.id} - ${author.name}`)
}
// 위 함수는 Post 인터페이스의 프로퍼티가 추가될때마다 수정해야하는 불편함 존재.
// -> 인덱스드 엑세스 타입 이용해 author의 프로퍼티 타입을 추출!
function printAuthorInfo(author: Post["author"]) {
console.log(`${author.id} - ${author.name}`)
}
// 인덱스 중첩 사용도 가능
function printAuthorInfo(author: Post["author"]["id"]) {
// author 매개변수의 타입은 number 타입이 됨
console.log(`${author.id} - ${author.name}`);
}
- 주의사항
- 인덱스에는 타입만 들어갈 수 있음. 문자열값을 변수에 저장해서 인덱스처럼 쓰려고 하면 x
- 인덱스에 존재하지 않는 프로퍼티 이름 쓰면 x
// 오류1
const authorKey = "author";
function printAuthorInfo(author: Post[authorKey]) {
console.log(`${author.id} - ${author.name}`);
}
// 오류2
function printAuthorInfo(author: Post["what"]) {
console.log(`${author.id} - ${author.name}`);
}
※ 배열 요소의 타입 추출
type PostList = {
title: string;
content: string;
author: {
id: number;
name: string;
age: number;
};
}[];
const post: PostList[number] = {
title: "게시글 제목",
content: "게시글 본문",
author: {
id: 1,
name: "이정환",
age: 27,
},
};
※ 튜플의 요소 타입 추출
type Tup = [number, string, boolean];
type Tup0 = Tup[0]; // number
type Tup1 = Tup[1]; // string
type Tup2 = Tup[2]; // boolean
type Tup3 = Tup[number] // number | string | boolean
2. keyof & typeof 연산자
- 객체 타입으로부터 프로퍼티의 모든 key를 String Literal Union 타입으로 추출하는 연산자
- 오직 타입에만 사용 가능
interface Person {
name: string;
age: number;
}
const person: Person = {
name: "이정환",
age: 27,
};
// 이렇게 만들면 Person 인터페이스에 프로퍼티 수정될때마다 함수 매개변수도 바꿔야 함
function getPropertyKey(person: Person, key: "name" | "age") {
return person[key];
}
// -> keyof 연산자 사용해서 수정!
function getPropertyKey(person: Person, key: keyof Person) {
return person[key];
}
3. 맵드 타입
- 객체 타입을 기반으로 새로운 객체 타입을 만드는 타입 조작 기능.
interface User {
id: number;
name: string;
age: number;
}
// 이렇게 쓰면 User 인터페이스와 중복되는 코드 많음.
type PartialUser = {
id?: number;
name?: string;
age?: number;
}
// -> 맵드 기능 활용!
type PartialUser = {
[key in "id" | "name" | "age"]?: User[key];
};
// -> 위 코드를 keyof 연산자를 이용해 한 번 더 수정
type PartialUser = {
[key in keyof User]?: User[key];
};
function updateUser(user: PartialUser) {
// ... 유저 정보 수정 기능
}
// 필요한 프로퍼티만 가져올 수 있음
updateUser({
age: 25
});
4. 템플릿 리터럴 타입
- 템플릿 리터럴을 이용해 특정 패턴을 갖는 String 타입을 만드는 기능
type Color = "red" | "black" | "green";
type Animal = "dog" | "cat" | "chicken";
// coloredAnimal : color 타입과 animal 타입을 조합해서 만들 수 있는 모든 가짓수.
// 두 타입의 프로퍼티가 많아질수록 수정해야 됨.
type ColoredAnimal = `red-dog` | 'red-cat' | 'red-chicken' | 'black-dog' ... ;
// -> 템플릿 리터럴 타입 사용!
type ColoredAminal = `${Color}-${Animal}`;
5. 조건부 타입
- extends와 삼항 연산자를 이용해 조건에 따라 각각 다른 타입을 정의하도록 돕는 문법.
type A = number extends string ? number : string;
// number 타입이 string 타입의 서브타입이니? -> 아니오
// 그러니 type A는 string 타입이 된다!
- 제네릭과 함께 사용할 때 효율적!
type StringNumberSwitch<T> = T extends number ? string : number;
let varA: StringNumberSwitch<number>; // string
let varB: StringNumberSwitch<string>; // number
※ infer
- 조건부 타입 내에서 특정 타입을 추론하는 문법
- Return Type(특정 함수 타입에서 반환값의 타입만 추출하는 조건부 타입)을 만들때 이용
type ReturnType<T> = T extends () => infer R ? R : never;
type FuncA = () => string;
type FuncB = () => number;
type A = ReturnType<FuncA>;// string
type B = ReturnType<FuncB>;// number'개발공부' 카테고리의 다른 글
| String.prototype.padStart() (0) | 2025.03.28 |
|---|---|
| [공식문서 읽기/API] LocalStorage / Geolocation (0) | 2025.03.17 |
| #7. 제네릭 (0) | 2025.02.28 |
| #6. 클래스 (0) | 2025.02.27 |
| #5. 인터페이스 (0) | 2025.02.26 |