TypeScript의 교차 타입은 여러 타입을 결합하여 모든 속성과 제약 조건을 모두 포함하는 새로운 타입을 생성합니다. 이는 각 타입의 속성과 특성을 병합하여 단일 타입으로 만듭니다.
교차 타입은 결합된 타입의 속성을 강제합니다.
API 응답 타입 정의 등에서 공통 속성을 공유하는 타입을 설계할 때 특히 유용합니다.
interface ErrorMessage {
success: boolean;
error?: {
message: string;
}
}
interface UserData {
users: {
name: string;
}[];
}
interface PostsData {
posts: {
title: string;
// ...
}[];
}
// 교차 타입 정의
type UsersResponse = UserData & ErrorMessage;
type PostsResponse = PostsData & ErrorMessage;
const userResponse: UsersResponse = {
success: true,
users: [{ name: "MinJae" }, { name: "MJ" }],
};
const postResponse: PostsResponse = {
success: false,
error: {
message: "Failed to fetch posts.",
},
posts: [],
};
UsersResponse
타입은 UserData
와 ErrorMessage
를 결합한 결과입니다. 따라서 users
속성과 success
, error
속성을 모두 포함합니다.PostsResponse
타입은 PostsData
와 ErrorMessage
를 결합하여 posts
속성과 ErrorMessage
속성을 포함합니다.유니온 타입은 하나 이상의 타입 중 하나를 선택할 수 있도록 허용하는 TypeScript의 중요한 기능입니다. 유니온 타입은 |
연산자를 사용하여 정의합니다.
let value: string | number;
value = "Hello"; // 유효
value = 42; // 유효
value = true; // 오류: 'boolean'은 할당할 수 없음
유니온 타입은 조건문이나 TypeScript의 타입 가드를 사용하여 특정 타입으로 좁힐 수 있습니다. 이를 통해 변수의 타입에 따라 적절한 로직을 수행할 수 있습니다.
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase()); // id가 string일 때
} else {
console.log(id.toFixed(2)); // id가 number일 때
}
}
printId("12345"); // 출력: "12345"
printId(42); // 출력: "42.00"
특정 조건에 따라 타입을 반환합니다. TypeScript에서 타입 로직을 표현할 수 있습니다.
type IsString<T> = T extends string ? true : false;
type Result1 = IsString<string> // true
type Result2 = IsString<number> // false
TypeScript의 유틸리티 타입은 기본 타입을 변형하거나 새로운 타입을 생성할 수 있는 강력한 도구입니다. 이들 타입은 코드의 간결함과 재사용성을 높이는 데 유용합니다.
Partial<T>
Partial
은 주어진 타입의 모든 속성을 선택적으로 바꿉니다.
주로 객체를 부분적으로 업데이트할 때 유용합니다.
interface Todo {
title: string;
desc: string;
completed: boolean;
}
type PartialTodo = Partial<Todo>
const updateTodo: PartialTodo = {
title: "Update TypeScript Guide", // 일부 속성만 제공 가능
};
Required<T>
Required
는 주어진 타입의 모든 선택적 속성을 필수로 만듭니다.
interface Todo {
title: string;
description?: string; // 선택적 속성
}
type RequiredTodo = Required<Todo>;
const todo: RequiredTodo = {
title: "Learn TypeScript",
description: "Understand utility types", // 이제 필수
}
Pick<T, K>
Pick
은 주어진 타입에서 특정 속성만 선택하여 새로운 타입을 만듭니다.
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Write blog post",
completed: false,
};
Omit<T, K>
Omit
은 주어진 타입에서 특정 속성을 제외한 새로운 타입을 만듭니다.
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Write blog post",
completed: false,
};
외에도 Readonly
, Record
, Exclude
, Extract
, NonNullable
등 여러 유틸리티 타입이 있습니다.
타입 추론은 TypeScript가 코드에서 변수, 함수, 객체 등의 타입을 자동으로 결정하는 기능입니다. TypeScript는 코드 내에서 제공되는 값을 기반으로 타입을 추론하기 때문에 명시적으로 타입을 지정하지 않아도 코드가 작동합니다.
타입 추론은 코드의 가독성과 개발 경험을 높이는 동시에 타입 체크를 유지하기 위해 TypeScript가 제공하는 중요한 기능입니다.
const num = 42; // TypeScript는 `num`의 타입을 number로 추론합니다.
const str = "TypeScript"; // TypeScript는 `str`의 타입을 string으로 추론합니다.
const isReady = true; // TypeScript는 `isReady`의 타입을 boolean으로 추론합니다.
const add = (a: number, b: number) => a + b; // TypeScript는 `a`, `b`, 그리고 반환 값의 타입을 number로 추론합니다.
const result = add(5, 10); // TypeScript는 `result`의 타입이 number임을 추론합니다.
타입 가드(Type Guards)란 코드에서 특정 조건을 통해 유니언 타입이나 다형성 타입을 좁히는 기법입니다.
TypeScript에서 타입 가드를 사용하면 코드 내에서 조건 분기(if 문)를 통해 타입 좁히기를 수행할 수 있습니다.
이를 통해 TypeScript는 코드 실행 중 변수의 타입을 더욱 정확하게 인식하고 타입 체크를 수행할 수 있습니다.
function isString(value: unknown): value is string {
return typeof value === "string";
}
function print(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase()); // string으로 좁혀짐
} else {
console.log(value.toFixed(2)); // number로 좁혀짐
}
}
print("hello"); // 출력: HELLO
print(42); // 출력: 42.00
TypeScript는 JavaScript 내장 연산자를 통해 제공되는 여러 가지 타입 검사 기능(typeof
, instanceof
, in
)을 타입 가드로 활용할 수 있습니다.
function isNumber(value: unknown): value is number {
return typeof value === "number";
}
function checkValue(value: string | number) {
if (isNumber(value)) {
console.log(value.toFixed(2));
} else {
console.log(value.toUpperCase());
}
}
class Dog {
bark() {
console.log("Woof");
}
}
class Cat {
meow() {
console.log("Meow");
}
}
function isDog(animal: Dog | Cat): animal is Dog {
return animal instanceof Dog;
}
function interactWithAnimal(animal: Dog | Cat) {
if (isDog(animal)) {
animal.bark();
} else {
animal.meow();
}
}
const myDog = new Dog();
const myCat = new Cat();
interactWithAnimal(myDog); // Woof
interactWithAnimal(myCat); // Meow
✅ 참고