231212 TIL

chillakilla·2023년 12월 13일

TypeScript 4주차 강의

고급 타입 활용하기

enum

  • enum은 열거형 데이터 타입.

  • 상수(const)의 그룹화 시, 사용하기 아주 좋은 타입.

  • enum 타입은 코드의 가독성을 높이고, 명확한 상수 값을 정의할 수 있다.

  • 컴파일 시, 자동으로 숫자 값으로 매핑되므로 따로 값을 할당할 필요가 없다.
    *하지만 특정 숫자 값으로 매핑되어야만 한다면, 그것은 직접 할당해주면 된다.

  • 예시

<script>
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);
</script>

관리 권한, 사용자 권한에 대한 코드 작성 시 확실하게 적절해 보인다.


object literal

  • 겉으로 보면 enum과 흡사, 하지만 키워드는 const/let 사용 가능.
  • 객체 리터럴은 key+value의 pair로 구성된 객체를 정의하는 방식.
  • 예시
<script>
const obj = {
  a: [1,2,3],
  b: 'b',
  c: 4
}
</script>
  • 예제 코드로 보면 a, b, c 라는 key 에 각각 [1,2,3,], 'b', 4 의 value가 바인딩 되어있음.

  • enum에 비해서 object literal이 가지는 장점?
    enum의 각 멤버는 상수였기 때문에 number, string 타입의 값만 대입이 가능했다.
    하지만 object literal에서는 어떤 타입의 값도 대입을 할 수 있다.
    즉, 다양한 데이터 타입의 지원으로 유연한 구조를 지닐 수 있다는 말.
    또한, 코드 내에서 사용하기 전에 값이 할당되어야 하므로, 런타임 에러 방지할 수 있다.


그렇다면 언제 enum 을 사용하고 어떨 때 object literal을 사용해야 할까?

enum을 사용하면 좋은 경우

  • enum은 간단한 상수 값을 그룹화해서 관리할 때.
  • 대신, enum은 상수 값이기 때문에 각 멤버의 값이 변하면 안된다는 조건이 달림.

object literal을 사용하면 좋은 경우

  • object literal은 멤버의 값이나 데이터 타입을 맘대로 변경할 수 있다.
  • 복잡한 구조와 다양한 데이터 타입을 사용해야 할 때.

유틸리티 타입 훑어보기

  1. Partial<T>

  • Partial<T> 타입은 타입 T의 모든 속성을 선택적으로 만든다.

  • 이를 통해서 기존 타입의 일부 속성만 제공하는 객체를 쉽게 생성할 수 있다.

  • 사용 사례

<script>
interface Person {
  name: string;
  age: number;
}

const updatePerson = (person: Person, fields: Partial<Person>): Person => {
  return { ...person, ...fields };
};

const person: Person = { name: "Spartan", age: 30 };
const changedPerson = updatePerson(person, { age: 31 });
</script>
  1. Required<T>

  • Partial<T> 타입과는 반대로 타입 T의 모든 속성을 필수적으로 만듭니다.
  • T 타입 객체에 정의된 모든 속성이 반드시 전부 제공이 되는 객체를 생성해야할 때 쓰인다.
  • 사용 사례
<script>
interface Person {
  name: string;
  age: number;
  address?: string; // 속성 명 뒤에 붙는 ?가 뭘까요
}
</script>
  • address? 에서 ? 는 선택적 속성, 있어도 되고 없어도 되는 녀석.
  • 하지만 address를 필수적으로 받아야한다면, type RequiredPerson = Required<Person>;
  1. Readonly<T>

  • Readonly<T> 는 타입 T의 모든 속성을 읽기 전용으로 만든다.
  • 이를 통해 Readonly 타입의 속성들로 구성된 객체가 아니어도, 완전한 불변 객체로 취급할 수 있다.
  • 사용 사례
<script>
interface DatabaseConfig {
  host: string;
  readonly port: number; // 인터페이스에서도 readonly 타입 사용 가능해요!
}

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

const immutableConfig: Readonly<DatabaseConfig> = {
  host: "localhost",
  port: 3306,
};

mutableConfig.host = "somewhere";
immutableConfig.host = "somewhere"; // 오류!
</script>
  1. Pick<T,K>

  • Pick<T,K> 유틸리티 타입은 타입 T에서 K 속성들만 선택하여 새로운 타입을 만듦.
  • 이를 통해 타입의 일부 속성만을 포함하는 객체를 쉽게 생성할 수 있다.
  • 사용 사례
<script>
interface Person {
  name: string;
  age: number;
  address: string;
}

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

const person: SubsetPerson = { name: "Spartan", age: 30 };
</script>
  • SubsetPerson은 Person이라는 인터페이스에서 name, age 속성만 선택해서 구성된 새로운 타입.
  1. Omit<T,K>

  • Omit<T,K> 유틸리티 타입은 타입 T에서 K 속성들만 제외한 새로운 타입을 만듦.
  • Pick<T,K> 유틸리티 타입과는 반대.
  • 이를 통해, 기존 타입에서 특정 속성을 제거한 새로운 타입을 쉽게 생성할 수 있다.
  • 사용 사례
<script>
interface Person {
  name: string;
  age: number;
  address: string;
}

type SubsetPerson = Omit<Person, "address">;

const person: SubsetPerson = { name: "Alice", age: 30 };
</script>
  • SubsetPerson 타입은 Person 타입에서 address 속성만 제외한 새로운 타입.

본격적인 TypeScript 실습에 들어가기 전에 정리할 시간이 필요하다고 판단했다.

물론 이것으로 정리가 되어 언제든 뚝딱뚝딱 손에서 나오진 않겠지만, 차곡차곡 쌓는다는 개념부터 시작하자는 마인드다.

profile
꾸준하려 하는 쉽덕놈

0개의 댓글