본문 바로가기
웹/TypeScript

[TypeScript/타입스크립트] 기본 문법 정리 -2

by 보먀 2024. 6. 19.
728x90
반응형

 

리터럴 타입

 

var 또는 let 으로 변수를 선언할 경우 이 변수의 값이 변경될 가능성이 있음을 컴파일러에게 알린다. 반면, const 로 변수를 선언하게 되면 TypeScript 에게 이 객체는 절대 변경되지 않음을 알린다. 그렇기 때문에 const 로 선언된 변수는 number, string 과 같은 기본 타입이 아닌 변수 값 자체가 타입이 되는데, 이것을 리터럴 타입이라고 부른다. 각 리터럴 타입은 number, string 같은 더 큰 타입에 포함된다. 

const name = 'codeit'; // 'codeit' 이라는 리터럴 타입
const rank = 1; // 1 이라는 리터럴 타입

 

 

 

타입 별칭

 

타입 별칭은 복잡한 타입에 이름을 붙여 재사용하고 싶을 때 사용한다. 타입 별칭은 type 뒤에 별칭을 쓰고 = 연산자 뒤에 타입을 정의하는 방식으로 사용할 수 있다. 별칭은 다른 변수와 차별화를 위해 관습적으로 대문자로 시작한다. 

type Point = [number, number];
type SearchQuery = string | string[];
type Result = SuccessResult | FailedResult;
type Coupon = 
  | PromotionCoupon
  | EmployeeCoupon
  | WelcomCoupon
  | RewardCoupon
  ;

 

 

 

Union

 

A 이거나 B 인 경우를 타입으로 만들고 싶을 때 사용한다. 아래의 코드에서 함수의 매개변수 product 는 ClothingProduct 또는 ShoeProduct 둘 중 하나의 타입이면 된다.

function func(product: ClothingProduct | ShoeProduct) {
  // ...
}

 

그럼 ClothingProduct 또는 ShoeProduct 두 타입 중 하나에만 있는 프로퍼티에 대한 내용은 어떻게 작성해야 할까? 

if 문에 in 키워드를 사용해서 해당 프로퍼티가 있는지 검사하면 된다. 이런 식으로 타입의 범위를 좁히는 것을 Type Narrowing 이라고 한다. 

interface A {
  a: string;
}

interface B {
  b: number;
}

function printAUnionB(arg: A | B) {
  // 여기서는 타입 A | B

    if ('a' in arg) {
    // 여기 안에서는 타입 A
    console.log(arg.a);
  }

    if ('b' in arg) {
    // 여기 안에서는 타입 B
    console.log(arg.b); // VS Code에서 arg에 마우스를 호버해 보세요.
  }
}

 

 

 

Intersection

 

A 와 B 의 성질을 모두 갖는 타입을 만들고 싶을 때 사용한다. 

interface Entity {
  id: string;
  createdAt: Date;
  updatedAt: Date;
}

type Product = Entity & {
  name: string;
  price: number;
  membersOnly?: boolean;
}

 

하지만, 보통 이럴 때는 interface 와 상속을 사용하는 것을 권장한다.

interface Entity {
  id: string;
  createdAt: Date;
  updatedAt: Date;
}

interface Product extends Entity {
  name: string;
  price: number;
  membersOnly?: boolean;
}

 

 

 

※ Union 과 Intersection 

 

  • A | B -> A 타입이거나 B 타입
  • A & B -> A 타입이랑 B 타입을 합친 것

근데 헷갈리는 것이 있다. 수학에서 배웠던 집합을 떠올려보면 Union(합집합), Intersection(교집합)과 같은 용어를 떠올려보면 아래와 같은 그림이 떠오른다. 아래의 그림을 생각하면 Union 은 두 타입을 합치고 Intersection 은 두 타입의 공통된 부분만 가져야 할 것 같다. 

 

 

Structural Subtyping

 

타입스크립트에서 타입은 Structural Subtyping 이라는 규칙을 따른다. 쉽게 말해 구조가 같으면 같은 타입이라고 판단하는 것이다. 

타입 A 는 a 라는 프로퍼티를 가지고 있고 변수 x, z, w 에 담겨있는 있는 각 객체에는 a 라는 프로퍼티가 존재한다. 그래서 타입 A 의 a 프로퍼티를 출력하는 printA 함수에 x, z, w 변수를 넣고 실행해도 올바른 타입이지만, a 프로퍼티가 없는 변수 y 에 담긴 객체로 실행하면 타입에러가 발생한다. 

 

이처럼 객체에 a 라는 프로퍼티가 있기 때문에 타입 A 라고 판단하는 것을 Structural Subtyping, Structural Type System 이라고 한다. (쉽게 말해 같은 것이 있으면 같은 타입으로 판단한다는 것)

interface A {
  a: string;
}

interface B {
  b: number;
}

function printA(arg: A) {
  console.log(arg.a);
}

const x = { a: 'codeit' };
const y = { b: 42 };
const z = { a: 'codeit', b: 42 };
const w = { a: 'codeit', b: 42, c: true };

printA(x);
printA(y); // 잘못된 타입
printA(z);
printA(w);

 

 

- Union 타입 

 

 

- Intersection 타입

 

 

 

keyof 연산자

 

객체 타입에서 프로퍼티 이름들을 모아서 Union 한 개의 Union 타입으로 만들고 싶을 때 사용한다. 

interface Product {
  id: string;
  name: string;
  price: number;
  membersOnly?: boolean;
}

type ProductProperty = keyof Product; // 'id' | 'name' | 'price' | 'membersOnly';

 

 

typeof 연산자

 

자바스크립트 코드에서 사용하면 결괏값이 문자열이지만, 타입스크립트 코드에서 쓸 때는 결과 값은 타입스크립트의 타입이다. 

// js 코드
const product: Product = {
  id: 'c001',
  name: '코드잇 블랙 후드 집업',
  price: 129000,
  salePrice: 98000,
  membersOnly: true,
};

console.log(typeof product); // 문자열 'object'
// ts 코드
const product: Product = {
  id: 'c001',
  name: '코드잇 블랙 후드 집업',
  price: 129000,
  salePrice: 98000,
  membersOnly: true,
};

const product2: typeof product = { // 타입스크립트의 Product 타입 -> 특정 객체 타입으로 사용할 수 있다
  id: 'g001',
  name: '코드잇 텀블러',
  price: 25000,
  salePrice: 19000,
  membersOnly: false,
};
728x90
반응형