보다 더 생생한 기록

[TS][공부 마라톤] 타입스크립트 학습 정리 본문

JavaScript[TS]

[TS][공부 마라톤] 타입스크립트 학습 정리

viviviviviid 2024. 6. 23. 00:05
최근 GO를 사용하다보니, JS에서 무수히 발생하는 타입에러들이 보기 싫어진 것과
부족한 스택을 채워야한다는 생각에 시작한 타입스크립트 공부.
이 내용이 끝나면 Nest.js + TypeORM을 진행해 프로젝트로 진행할 예정이다.

공부 마라톤 개요

학습 내용 : TypeScript, Nest.js, TypeORM

학습 기간 : 1개월

 

새로 안 사실만 블로깅

 

TypeScript Basic

  1. Call Signature
  2. Overloading
  3. Polymorphism(다형성) → 여러 형태
TypeScript의 제네릭(Generic)을 사용하면 다양한 타입을 사용할 수 있다. 제네릭은 선언 시점이 아니라 생성 시점에 타입을 명시하여 하나의 타입만이 아닌 여러 타입을 지원하는 기법이다.
type SuperPrint = {
    <TypePlaceholder>(arr: TypePlaceholder[]): TypePlaceholder
}

 

여기서 <TypePlaceholder>는 제네릭으로, 이름은 마음대로 작명 가능하다. 이 코드는 TypeScript가 타입을 자동으로 감지하여 배열의 첫 번째 요소의 타입을 반환한다.

 

const superPrint: SuperPrint = (arr) => arr[0];

const a = superPrint([1, 2, 3, 4]);
const b = superPrint([true, false, true]);
const c = superPrint(["a", "b", "c"]);
const d = superPrint([1, 2, true, "heehh"]);

 

제네릭은 any와 다르다. any는 타입 체크가 없지만, 제네릭은 타입 체크가 가능하여 코드의 안정성을 높인다.

 

type SuperPrint = {
    <T, S>(a: T[], b: S): T
}

const superPrint: SuperPrint = (arr) => arr[0];

const a = superPrint([1, 2, 3], "axxx");

 

Generic의 다른 형태 선언

일반적인 함수형 Generic 선언도 가능하다.

function superPrint<V>(a: V[]): V {
    return a[0];
}

const a = superPrint([1, 2, 3]);
type Player<Lalala> = {
    name: string;
    extraInfo: Lalala;
}
type NicoExtra = {
    favFood: string;
}
type NicoPlayer = Player<NicoExtra>;

const nico: NicoPlayer = {
    name: "nico",
    extraInfo: {
        favFood: "kimchi"
    }
}

const lynn: Player<null> = {
    name: "lynn",
    extraInfo: null
}

 

기존에 있는 Generic 사용하기

function ffff(arr: number[]): void;
function ffff(arr: Array<number>): void;

 

4. 객체 지향 - 클래스(Class)

TypeScript의 클래스는 자바스크립트의 클래스를 확장하여 타입과 접근 제어를 제공한다.

  • constructor의 매개변수를 지정하면, 자동으로 this에 할당된다.
  • 추상 클래스와 추상 메서드는 상속받는 클래스가 반드시 구현해야 하는 메서드를 정의한다.
type Words = {
    [key: string]: string
}

class Dict {
    private words: Words;

    constructor() {
        this.words = {};
    }

    add(word: Word) {
        if (this.words[word.term] === undefined) {
            this.words[word.term] = word.def;
        }
    }

    def(term: string): string {
        return this.words[term];
    }

    del(term: string): void {
        delete this.words[term];
    }

    update(word: Word): void {
        if (this.words[word.term] !== undefined) {
            this.words[word.term] = word.def;
        }
    }
}

class Word {
    constructor(
        public term: string,
        public def: string
    ) {}
}

const ramen = new Word("ramen", "면으로 된 음식");
const dict = new Dict();

dict.add(ramen);
dict.def("ramen");

const newRamen = new Word("ramen", "쥰맛탱");
dict.update(newRamen);
dict.def("ramen");

dict.del("ramen");
dict.def("ramen");

 

5. 인터페이스

읽기 전용 속성을 사용하여 외부에서 수정할 수 없도록 할 수 있다.

 

class Word {
    constructor(
        public readonly term: string,
        public readonly def: string
    ) {}
}

 

Type vs Interface

타입과 인터페이스의 차이점은 타입이 더 다양하게 활용될 수 있다는 점이다. 인터페이스는 주로 객체의 형태를 설명하기 위해 사용된다.

interface Player {
    nickname: string;
    team: string;
    health: number;
}

type Player = {
    nickname: string;
    team: string;
    health: number;
}

 

Init Setting

TypeScript 프로젝트를 설정하는 방법을 소개한다.

npm i -D typescript
{
  "include": ["src"],
  "compilerOptions": {
    "outDir": "build",
    "target": "ES6",
    "strict": true,
    "lib": ["ES6", "DOM"],
    "allowJs": true
  }
}
npm run build

JsDoc

JavaScript 파일을 TypeScript처럼 타입 체크를 받을 수 있게 설정할 수 있다

// @ts-check

/**
 * Initializes the project
 * @param {object} config
 * @param {boolean} config.debug
 * @param {string} config.url
 * @returns {void}
 */
export function init(config) {
  return true;
}

package.json의 scripts를 수정하여 개발 환경을 설정할 수 있다.

"scripts": {
  "build": "tsc",
  "dev": "nodemon --exec ts-node src/index.ts",
  "start": "node build/index.js"
}

 

DefinitelyTyped

TypeScript 커뮤니티가 제공하는 타입 정의 파일을 설치하여, 기존의 JavaScript 라이브러리를 TypeScript에서 사용 가능하게 할 수 있다.

npm i -D @types/node
{
  "include": ["src"],
  "compilerOptions": {
    "outDir": "build",
    "target": "ES6",
    "strict": true,
    "lib": ["ES6"],
    "esModuleInterop": true,
    "module": "CommonJS"
  }
}