[TypeScript] Using Types(타입 사용하기)

Basic Type Usage

JavaScript

function jsCode(num1, num2) {
  return num1 + num2;
}

자바스크립트에서는 인자로 들어오는 num1과 num2에 정확히 어떤 타입의 값이 들어오고,
또 return값으로 어떤 타입의 값이 반환되는지 곧장 알기 힘들다.

function jsFetch(id) {
  // fetch code
  // fetch code
  // fetch code
  return new Promise((resolve, reject) => {
    resolve(100);
  });
}

이 코드 또한 fetch를 통해 어떤 코드가 반환되는지 한 눈에 알기 힘들고, 코드 전체를 들여다봐야만
반환값이 무엇인지 알 수 있다.

TypeScript

function tsCode(num1: number, num2: number): number {
  return num1 + num2;
}

타입스크립트에서는 인자로 들어오는 num1과 num2에 대한 타입이 명시되어 있고,
또 return값으로 어떤 타입의 값이 반환되는지도 명시되어 있기 때문에 코드를 한눈에 이해할 수 있다.

function tsFetch(id: string): Promise<number> {
  // fetch code
  // fetch code
  // fetch code
  return new Promise((resolve, reject) => {
    resolve(100);
  });
}

이 코드에선 인자로 string을 받아서 Promise를 반환하며 fetch가 완료된 다음에는
number 타입을 반환한다는 것을 첫 줄에서 바로 알 수 있다.

Optional, Default, Rest

Optional Parameter

function printName(firstName: string, lastName: string) {
  console.log(firstName);
  console.log(lastName);
}
printName("Ga", "Moon");
printName("Ga"); // error: Expected 2 arguments, but got 1.

타입스크립트에서는 함수에 인자 두 개를 정해줬을 때, 인자를 하나만 넣었을 경우 오류가 발생하게 된다.
하지만 인자가 하나가 들어가는 경우에도 코드가 실행되게 하고 싶은 경우 optional 인자를 사용할 수 있다.

function printName(firstName: string, lastName?: string) {
  // ? 를 추가하여 optional 인자로 설정했다.
  console.log(firstName);
  console.log(lastName);
}
printName("Ga", "Moon");
printName("Ga");
printName("Ga", undefined);

이렇게 하면 두번째 인자가 전달될 수도, 되지 않을 수도 있다는 코드가 된다. 따라서 인자를 입력하지 않아도 실행이 되고
undefined를 전달해도 문제 없이 실행이 된다.

Default Parameter

function printMessage(message: string = "default message") {
  // = 으로 default 인자를 추가해주었다.
  console.log(message);
}
printMessage();

인자에 아무것도 전달하지 않았을 때 기본값이 존재하길 원하는 경우 default 인자를 활용하면 된다.
이렇게 할 경우 인자에 아무것도 전달하지 않아도 'default message'가 출력된다.
Optional 인자에서는 아무것도 전달하지 않을 경우 undefined가 반환되는 것과 차이가 있다.

Rest Parameter

function addNumbers(...numbers: number[]): number {
  // 전개 구문을 활용하여 number타입으로 이루어진 배열이라는 rest 인자를 추가했다.
  return numbers.reduce((a, b) => a + b);
}
console.log(addNumbers(1, 2)); // 3
console.log(addNumbers(1, 2, 3)); // 6
console.log(addNumbers(1, 2, 3, 4)); // 10

인자에 전달하고 싶은 값의 개수가 상황에 따라 다르다면 rest 인자를 활용하면 된다.
...(전개 구문, Spread Syntax)를 활용하여 인자에 전달되는 numbers는 number로 이루어진 배열([])이라고 설정해주면
인자에 들어오는 number값들이 배열화되고 그 안에 들어오는 값이 몇 개든 활용할 수 있게 된다.

Array, Tuple

Array

const people: string[] = ["Moon", "Kim", "Lee"];
const age: Array<number> = [20, 22, 24];

타입스크립트에서 배열을 정의하는 방법에는 이렇게 두가지가 있다.
이 두 방법에는 큰 차이가 없지만 함수를 만들 때는 첫 번째 방법이 더 유용하다.

function print(people: string[]) {
  people.push("Park");
  console.log(people);
}

이러한 코드가 있을 때 주어진 데이터가 함부로 함수 내부에서 변경되거나 업데이트 되지 않도록 하려면
readonly를 붙여주면 된다.

function print(people: readonly string[]) { // readonly를 추가
  people.push('Park'); // error: Property 'push' does not exist on type 'readonly string[]'.
  console.log(people);
};

이렇게 readonly를 추가하면 데이터의 불변성을 보장할 수 있게 된다.

Tuple

let info: [string, number];
info = ["Moon", 20];
info[0]; // 'Moon'
info[1]; // 20

튜플을 사용하면 하나의 변수에 서로 다른 타입의 데이터를 담을 수가 있다. 얼핏 보기엔 활용도가 높아 보이지만,
이에 접근을 할 때 배열처럼 인덱스를 사용해야 한다는 점 때문에 가독성이 떨어지는 문제점이 있다.
따라서 되도록이면 interface, type alias, 혹은 class를 사용하는 것이 좋으나 굳이 사용하겠다면
object destructuring을 사용하는 방법도 있다.

const [name, age] = info;

이렇게 할 경우 info.nameinfo.age로 접근이 가능해져 가독성이 나아진다.
하지만 결국 선언하는 시점과 가독성을 개선하는 시점이 다르다기 때문에 효율성이 여전히 떨어진다고 볼 수 있다.

Categories:

Published: