TypeScript

고급 타입

차돌박이츄베릅 2023. 7. 27. 06:34

enum과 object literal

  • enum(이넘)은 '간단한 상수 값'을 그룹화하여 관리할 때 적합.
    -> enum은 상수 값이기 때문에 각 멤버의 값이 변하면 안된다는 조건이 있음.
  • object literal(객체 리터럴)은 멤버의 값이나 데이터의 타입을 맘대로 변경할 수 있음.
    -> 복잡한 구조와 다양한 데이터 타입을 사용할 땐 객체 리터럴 사용ㄱ 

 

enum은 열거형 데이터 타입. 상수의 그룹화할 때 좋음.

  • 코드의 가독성을 높이고 명확한 상수값을 정의할 수 있다.
  • 컴파일 시에 자동으로 숫자 값으로 매핑되므로 따로 값을 할당할 필요가 없다! 하지만, 특정 숫자 값으로 매핑되어야 하면 그것은 직접 할당을 해주시면 됨
enum UserRole {
  ADMIN = "ADMIN",
  EDITOR = "EDITOR",
  USER = "USER",
}

enum UserLevel {
  NOT_OPERATOR, // 0
  OPERATOR // 1
}

function checkPermission(userRole: UserRole, userLevel: UserLevel): void {
  if (userLevel === UserLevel.NOT_OPERATOR) {
    console.log('당신은 일반 사용자 레벨이에요');
  } else {
    console.log('당신은 운영자 레벨이군요');
  } 

  if (userRole === UserRole.ADMIN) {
    console.log("당신은 어드민이군요");
  } else if (userRole === UserRole.EDITOR) {
    console.log("당신은 에디터에요");
  } else {
    console.log("당신은 사용자군요");
  }
}

const userRole: UserRole = UserRole.EDITOR;
const userLevel: UserLevel = UserLevel.NOT_OPERATOR;
checkPermission(userRole, userLevel);

 

 


유틸리티 타입

별칭을 사용하여 새로운 타입을 정의

 

1) Partial<T>

파셜

제네릭???이 뭔데??

T자리에 type을 넣으면 됨

 

Partial에는
name속성만 있어도 되고, age속성만 있어도 되고, name과 age 둘 다 있어도 되지만
여기에 존재하지 않는 속성(gender..)은 넣을 수 없음

Partial 타입으로 유연하게 타입의 속성을 선택하여 객체를 만들 수 있음!

// 인터페이스
// 객체의 구조를 정의하는 데 사용
interface Person {
  name: string;
  age: number;
}

// fields는 Partial으로 타입을 정의해둠.
// 이러면 name, age 둘다 혹은 하나만 들어가도 됨
const updatePerson = (person: Person, fields: Partial<Person>): Person => {
  return { ...person, ...fields };
};

// person을 만들때는 속성을 풀로 정의해야했음. name, age 모두
const person: Person = { name: "Spartan", age: 30 };

// changedPerson할 때는 선택적으로 age만 쓸 수 있음
const changedPerson = updatePerson(person, { age: 31 });


2) Required<T>

타입 T의 모든 속성을 필수적으로 만듦
즉, 모든 속성이 반드시 전부 제공이 되어야 되는 객체를 생성할 때 사용

interface Person {
  name: string;
  age: number;
  address?: string; // ?는 선택적 속성임. 있어도 되고 없어도 된다는 뜻
}

// 그러나 address까지 필수적으로 받고싶다면 Requierd<>사용하면 address 입력까지 필수가 됨
type RequiredPerson = Required<Person>;


3) Readonly<T>

객체의 상수화
타입T의 모든 속성을 읽기 전용(read-only)로 만듦.
readonly타입의 속성으 구성된 객체가 아니더라도 완전한 불변 객체로 취급할 수 있음!

// DatabaseConfig는 불변 객체가 아님(host속성이 readonly가 아니기때문)
// ReadOnly<T>타입을 이용해 불변 객체로 만들어 쓸 수 있다!
interface DatabaseConfig {
  host: string;
  readonly port: number; // 인터페이스에서도 readonly 타입 사용 가능해요!
}

const mutableConfig: DatabaseConfig = {
  host: "localhost",
  port: 3306,
};

const immutableConfig: Readonly<DatabaseConfig> = {
// DatabaseConfig를 Readonly<>로 감싼 유틸리티 타입이기 때문에 
// host속성은 interface에서는 readonly타입이 아니었지만 여기서는 얘도 readonly가 되어버렸음
  host: "localhost",
  port: 3306,
};

mutableConfig.host = "somewhere";
immutableConfig.host = "somewhere"; // 🚫오류! Readonly로 할당한거라 수정할 수 없기때문에 오류!!

 

4) Pick<T, K>

 

타입 T에서 K속성들만 선택하여 새로운 타입을 만듦
타입의 일부 속성만 '포함'하는 객체를 쉽게 생성할 수 있게 됨

interface Person {
  name: string;
  age: number;
  address: string;
}

type SubsetPerson = Pick<Person, "name" | "age">;

const person: SubsetPerson = { name: "Spartan", age: 30 };
// 원래의 Person에서는 모든 속성이 필수였으나
// Pick<>로 감싸서 "name"|"age" 일부를 포함하도록 새로운 타입을 만듦
// Person이란 타입에서 "name","age"중에서 취사선택 하겠다!!

 

5) Omit<T, K>

생략하다. 스킵.
타입 T에서 K속성들만 '제외'한 새로운 타입을 만듦.
Pick<t, k>과 반대되는 개념.</t, k>
기존 타입에서 특정 속성을 제거한 새로운 타입을 쉽게 생성할 수 있음.

interface Person {
  name: string;
  age: number;
  address: string;
}

// address속성만 제외하겠다(즉, name과 age만 받겠다)
type SubsetPerson = Omit<Person, "address">;

const person: SubsetPerson = { name: "Alice", age: 30 };

 

 

기타 유틸리티 타입: https://www.typescriptlang.org/ko/docs/handbook/utility-types.html