[Typescript] typescript 연습하기

2022. 7. 17. 18:38개발/Node & Javascript

728x90
반응형

개요

  1. typescript를 쓰다보면 실제로 효율적으로 쓰고 있는지 의심이 들 때가 있다.
  2. 이를 연습해볼 수 있는 곳이 있는데, type-challenges라는 repo에서 실제로 연습을 해볼 수 있다.

예제

아래는 몇가지 예제를 link를 걸어두었다.

  1. Pick
  2. ReadOnly

위의 문제들을 풀다보면 typescript의 다른 방식에 대해 애를 먹을 수 있는데, 이 특징과 몇가지 typescript의 문법들을 보면서 문제를 풀기전에 개념을 잡아보려고 한다.

typescript 특징

type programming이다.

일단 기본적으로 typescript는 javascript의 runtime 동작을 모델링 하는 언어입니다. 따라서 실제 runtime에서는 type들이 제거되고 javascript로 실행된다. 즉, 이를 구별하기 위해서는 type공간과 실제 runtime 공간을 구별해서 이해하는 것이 중요하다.

아래의 예제를 살펴보자.

interface A {
  item: number,
}

const a: A = {
  item: 1,
};

// Error
if (a instanceof A) {
  console.log('zzzz');
}

해당 예제를 typescript playground에서 실행해보면 에러 문구가 나오는 걸 볼 수 있다.
그리고 실제 컴파일된 결과를 보면 interface에 대한 정의가 사라져있는 것을 볼 수 있다.

"use strict";
// interface A {
//   item: number,
// }
const a = {
    item: 1,
};
if (a instanceof A) {
    console.log('zzzz');
}

위의 내용을 통해 유추할 수 있는점 들이 몇 개 있다.

  1. type operation들은 실제 런타임에 대해 영향을 주지 않는다.
  2. type에 정의되있더라도 실제 런타임에서는 잘못된 값을 받을 수 있다.

따라서 실제로 런타임 코드와 타입에 대한 코드를 구별해서 생각하는 것이 좋다.

집합으로 type을 표현한다.

typescript의 type은 기본적으로 집합의 요소로 type을 표현한다고 생각하면 좋다.
아래의 문제들을 통해서 어디서 에러가 표시될지 한 번 예측해보자.

interface A {
  a: number;
}

interface B {
  b: number;
}

type C = A | B; // 합집합, 합집합에서는 A 또는 B의 속성을 가지고 있으면 된다.

const e1: C = { a: 1 };
const e2: C = { b: 1 };
const e3: C = { a: 1, b: 1 };
const e4: C = { a: 1, b: 1, c: 1 };
const e5: C = { c: 1 };

type C는 A와 B의 합집합으로 생각하면 예측이 더 쉬울 것이다.

그렇다면 합집합을 봤으니 교집합도 존재한다.

interface A {
  a: number;
}

interface B {
  b: number;
}

type C = A & B; // 교집합, 교집합에서는 A와 B의 속성을 모두 가지고 있어야 한다.

const e1: C = { a: 1 };
const e2: C = { b: 1 };
const e3: C = { a: 1, b: 1 };
const e4: C = { a: 1, b: 1, c: 1 };
const e5: C = { c: 1 };

문법들

any, unknown, never type

  1. any는 어떤 타입도 허용하는 특수한 type.
  2. unknown은 어떤 타입이든 매칭이 될 수 있지만 말그대로 unkown이기 때문에 연산자나 method call에 있어서 에러를 뱉어낸다. 따라서 unknown으로 받고 정확한 타입 유추를 통해서 method를 사용하는 것이 좋다.
  3. never는 어떤 타입도 허용하지 않는 특수한 type이다.
type A = 'a' | 'b' | 'c'

type CustomExclude<T, P extends T> = T extends P ? never : T;

const e1:A = 'a';
const e2:A = 'b';
const e3:A = 'c';

const e4:CustomExclude<A, 'a'> = 'a'; // error
const e5:CustomExclude<A, 'a'> = 'b';
const e6:CustomExclude<A, 'a'> = 'c';
const e7:CustomExclude<A, 'd'> = 'c'; // error

extends

type 공간에서 extends는 해당 타입의 부분집합을 나타낼 때 사용한다.
class나 interface에서 사용하는 extends와는 다른 방식으로 생각해야 된다.

type A = 'a' | 'b' | 'c';
type C<T>= T extends A ? true : false;

const e1: C<'a'> = true;
const e2: C<'d'> = false;
const e3: C<'a' | 'b'> = true;
const e4: C<'a' | 'b' | 'c'> = true;
const e5: C<'a' | 'b' | 'c' | 'd'> = false;

keyof

type에서 keyof는 해당 타입의 속성을 열거할 때 사용한다.

interface A {
  a: number;
  b: number;
  c: number;
}

type AProp = keyof A;

const a: AProp = 'a';
const d: AProp = 'd'; // error
728x90
반응형