React + TS 01 | 타입스크립트 연습

Kate Jung·2021년 12월 25일
0

React

목록 보기
17/28
post-thumbnail

📌 새 JS 프로젝트 생성

# 터미널에서 입력할 명령어들

$ mkdir ts-practice # ts-practice 라는 디렉터리 생성
$ cd ts-practice # 해당 디렉터리로 이동
$ yarn init -y # 또는 npm init -y

ts-practice 디렉터리에 package.json 파일 형성

📌 타입스크립트 설정파일 생성

  • 위치 및 파일명

    위치: 프로젝트 디렉터리 내부
    파일명: tsconfig.json

  • 파일의 역할

    타입스크립트가 컴파일 될 때 필요한 옵션 지정

  • 코드

    {
      "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "strict": true,
        "esModuleInterop": true,
        "outDir": "./dist" // 추가된 속성
      }
    }
  • 생성 방법

    • 직접 입력

    • 명령어 사용 (일반적)

      1. typescript 를 글로벌로 설치

        $ yarn global add typescript

      2. 프로젝트 디렉터리 내부에서 tsc --init 입력 → tsconfig.json 파일 자동생성

        • 만약, 명령어 작동 x

          npm install -g typescript 하고 다시 명령어 실행

  • 설정의 의미

    • (tsc --init 를 통해) 기본적으로 설정된 것들의 의미

    • target

      컴파일된 코드가 어떤 환경에서 실행될 지 정의

      • ex
        target 설정es5es6
        화살표 함수 사용 시일반 function 키워드를 사용하는 함수로 변환유지
    • module

      컴파일된 코드가 어떤 모듈 시스템을 사용할지 정의

      • ex
        module 설정commones2015
        export default Sample 을 하게 됐을 때, 컴파일된 코드에서exports.default = helloWorld
         로 변환유지
    • strict

      모든 타입 체킹 옵션을 활성화

    • esModuleInterop

      commonjs 모듈 형태로 이루어진 파일을 es2015 모듈 형태로 불러올 수 있게 함.


    • outDir (속성 추가)

      컴파일된 파일들이 저장되는 경로를 지정

📌 타입스크립트 파일 생성

  • *.ts 란?

    타입스크립트가 사용하는 확장자

  1. 코드 작성 (src/practice.ts)
    const message: string = 'hello world';
    console.log(message);
  1. tsc 입력

    터미널에서 (해당 프로젝트의 디렉터리에 위치)

  2. 파일 생성됨 (dist/practice.js)

    ts 파일에서 명시한 값의 타입은 컴파일이 되는 과정에서 모두 사라짐.

    "use strict";
    var message = 'hello world';
    console.log(message);

📌 기본 타입

🔹 연습 코드

// src/practice.ts

let count = 0; // 숫자
count += 1;
count = '갑자기 분위기 문자열'; // 이러면 에러가 납니다!

const message: string = 'hello world'; // 문자열

const done: boolean = true; // 불리언 값

const numbers: number[] = [1, 2, 3]; // 숫자 배열
const messages: string[] = ['hello', 'world']; // 문자열 배열

messages.push(1); // 숫자 넣으려고 하면.. 안된다!

let mightBeUndefined: string | undefined = undefined; // string 일수도 있고 undefined 일수도 있음
let nullableNumber: number | null = null; // number 일수도 있고 null 일수도 있음

let color: 'red' | 'orange' | 'yellow' = 'red'; // red, orange, yellow 중 하나임
color = 'yellow';
color = 'green'; // 에러 발생!

🔹 결과

  • TS 사용 시

    → 특정 변수 or 상수 타입 지정 가능

    → 지정한 타입이 아닌 값 설정 시, 에러 발생

  • 에러 발생 시

    → 컴파일 불가

    → 컴파일 시도(tsc 입력) 하면 실패

📌 함수에서 타입 정의

🔹 연습 코드 1

// src/practice.ts

function sum(x: number, y: number): number {
  return x + y;
}

sum(1, 2);
  • TS 사용 특징

    • 코드 작성 과정 중, 함수의 파라미터로 어떤 타입을 넣어야 하는지 파악 가능

    • 함수 결과물의 타입

      : number (첫 줄 가장 우측)

      • 에러 예시

        결과물이 number 라고 명시 후, null 반환 → 오류


🔹 연습 코드 2

// src/practice.ts

// 숫자 배열의 총합

function sumArray(numbers: number[]): number {
  return numbers.reduce((acc, current) => acc + current, 0);
}
const total = sumArray([1, 2, 3, 4, 5]);
  • TS 사용 특징

    • 배열의 내장 함수 사용 시 → 타입 유추가 잘 이루어짐


    • 함수에서 아무것도 반환하지 않아야 한다면

      → 반환 타입: void로 설정

        function returnNothing(): void {
          console.log('I am just saying hello world');
        }

📌 interface 사용

interface란?
클래스 또는 객체를 위한 타입을 지정 할 때 사용되는 문법

🔹 클래스에서 interface 를 implements 하기

◾ 기본

// src/practice.ts

// interface 선언 (Shape)
interface Shape {
  getArea(): number; // Shape interface에는 getArea 함수 필수(반환값은 number)
}

class Circle implements Shape {
  // 'implements' 사용 -> 해당 클래스가 Shape interface의 조건을 충족하겠다는 것을 명시

  radius: number; // 멤버 변수 radius 값을 설정

  constructor(radius: number) {
    this.radius = radius;
  }

  // 너비를 가져오는 함수
  getArea() {
    return this.radius * this.radius * Math.PI;
  }
}

class Rectangle implements Shape {
  width: number;
  height: number;
  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  getArea() {
    return this.width * this.height;
  }
}

const Shapes: Shape[] = [new Circle(5), new Rectangle(10, 5)];

Shapes.forEach((shape) => {
  console.log(shape.getArea());
});
  1. tsc 입력

  2. 컴파일된 스크립트 실행 (node dist/practice 입력)

◾ 리팩토링

- 기존 코드

멤버 변수 선언 후, constructor에서 해당 값들 하나하나 설정

	width: number;
  height: number;
  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

- 리팩토링 코드

  • 직접 하나하나 설정하는 작업 생략 가능

    constructor의 파라미터 쪽에 public 또는 private accessor 사용

  • 코드

    // interface 선언 (Shape)
    interface Shape {
      getArea(): number; // Shape interface에는 getArea 함수 필수(반환값은 number)
    }
    
    class Circle implements Shape {
      // 'implements' 사용 -> 해당 클래스가 Shape interface의 조건을 충족하겠다는 것을 명시
    
      constructor(public radius: number) {
        this.radius = radius;
      }
    
      // 너비를 가져오는 함수
      getArea() {
        return this.radius * this.radius * Math.PI;
      }
    }
    
    class Rectangle implements Shape {
      constructor(private width: number, private height: number) {
        this.width = width;
        this.height = height;
      }
    
      getArea() {
        return this.width * this.height;
      }
    }
    
    const circle = new Circle(5);
    const rectangle = new Rectangle(10, 5);
    console.log(circle.radius); // 클래스 외부에서 조회 가능
    // console.log(rectangle.width); // 클래스 외부에서 조회 불가
    
    const Shapes: Shape[] = [new Circle(5), new Rectangle(10, 5)];
    
    Shapes.forEach((shape) => {
      console.log(shape.getArea());
    });
  • 설명

    조회 가능
    public
     으로 선언된 값클래스 외부
    private
    으로 선언된 값클래스 내부에서만
  • 실행

    1. 코드 컴파일 (tsc 입력)
    2. 실행 (node dist/practice 입력)
        C:\Users\admin\Documents\tmp_codingStudy\ts-practice>node 
        dist/practice
        5
        78.53981633974483
        50

🔹 일반 객체를 interface 로 타입 설정하기

◾ 기본

// src/practice.ts
interface Person {
  name: string;
  age?: number; // ?은 설정에 대한 옵션을 의미함. (해도 되고 안해도 되고)
}
interface Developer {
  name: string;
  age?: number;
  skills: string[];
}

const person: Person = {
  name: "김사람",
  age: 20,
};

const expert: Developer = {
  name: "김개발",
  skills: ["javascript", "react"],
};

◾ 리팩토링

  • extends

    상속 받기

    • 유사한 형태일 때

      interface 선언 시, 다른 interface 를 extends 키워드를 사용해서 상속 받기 가능

  • 코드

    interface Person {
      name: string;
      age?: number; // ?은 설정에 대한 옵션을 의미함. (해도 되고 안해도 되고)
    }
    interface Developer extends Person {
      skills: string[];
    }
    
    const person: Person = {
      name: "김사람",
      age: 20,
    };
    
    const expert: Developer = {
      name: "김개발",
      skills: ["javascript", "react"],
    };
    
    const people: Person[] = [person, expert];

📌 Type Alias 사용

type 이란?
특정 타입에 별칭을 붙이는 용도로 사용

  • type 기능

    • 객체를 위한 타입을 설정 가능
    • 배열, 또는 그 어떤 타입이던 별칭 제작 가능
  • 예시 코드

    type Person = {
      name: string;
      age?: number; // ?은 설정에 대한 옵션을 의미함. (해도 되고 안해도 되고)
    };
    
    // &은 Intersection 으로서 두 개 이상의 타입들을 합침.
    type Developer = Person & {
      skills: string[];
    };
    
    const person: Person = {
      name: "김사람",
    };
    
    const expert: Developer = {
      name: "김개발",
      skills: ["javascript", "react"],
    };
    
    type People = Person[]; // Person[]은 앞으로 People이라는 타입으로 사용 가능
    const people: People = [person, expert];
    
    type Color = "red" | "orange" | "yellow";
    const color: Color = "red";
    const colors: Color[] = ["red", "orange"];

📌 interface vs type

interfacetype
사용하는 것이 좋은 경우클래스 관련 타입일반 객체 타입
  • 객체를 위한 타입 정의 시 → 무엇이든 써도 상관 x,

    일관성 있게 사용

📌 Generics

제너릭(Generics)이란?
타입스크립트에서 함수, 클래스, interface, type alias 를 사용하게 될 때 여러 종류의 타입에 대하여 호환을 맞춰야 하는 상황에서 사용하는 문법

🔹 함수에서 사용

◾ 예시 상황 1

  • 가정

    객체 A 와 객체 B 를 합쳐주는 merge라는 함수 제작

  • A, B 가 어떤 타입이 올 지 모름

  • 기존 코드

    • any 타입을 쓸 수도 있음
    • 한계
      • 타입 유추가 모두 깨짐
        → 결과가 any 라는 것 == merge안에 무엇이 있는지 알 수 없음
        → 이런 상황에 Generics 사용
    function merge(a: any, b: any): any {
      return {
        ...a,
        ...b,
      };
    }
    
    const merged = merge({ foo: 1 }, { bar: 1 });
  • 리팩토링 코드
    function merge<A, B>(a: A, b: B): A & B {
      return {
        ...a,
        ...b,
      };
    }
    
    const merged = merge({ foo: 1 }, { bar: 1 });

◾ 예시 상황 2

function wrap<T>(param: T) {
  return {
    param
  }
}

const wrapped = wrap(10);

◾ 효과

  • 파라미터로 다양한 타입을 넣기 가능
  • 타입 지원 지킬 수 있음

🔹 interface 에서 사용

interface Items<T> {
  list: T[];
}

const items: Items<string> = {
  list: ["a", "b", "c"],
};

🔹 type 에서 사용

interface 에서 Generics를 사용한것과 매우 유사

type Items<T> = {
  list: T[];
};

const items: Items<string> = {
  list: ['a', 'b', 'c']
};

🔹 클래스에서 사용

  • 예시 코드

    • Queue(데이터를 등록 할 수 있는 자료형)라는 클래스 제작

      먼저 등록(enqueue)한 항목을 먼저 뽑아올 수(dequeue) 있는 성질을 가짐

    class Queue<T> {
      list: T[] = [];
    
      get length() {
        return this.list.length;
      }
    
      enqueue(item: T) {
        this.list.push(item);
      }
    
      dequeue() {
        return this.list.shift();
      }
    }
    
    const queue = new Queue<number>();
    
    queue.enqueue(0);
    queue.enqueue(1);
    queue.enqueue(2);
    queue.enqueue(3);
    queue.enqueue(4);
    
    console.log(queue.dequeue());
    console.log(queue.dequeue());
    console.log(queue.dequeue());
    console.log(queue.dequeue());
    console.log(queue.dequeue());
    # 코드 컴파일 & 실행
    $ tsc
    $ node dist/practice
    
    0
    1
    2
    3
    4

참고

profile
복습 목적 블로그 입니다.

0개의 댓글