데브코스 28일차 ( 24.11.20 수 ) - Typescript

워니·3일 전
1

Programmers Front-end

목록 보기
27/27

[Section 03] Typescript 고급


< 01. readonly >

  • 속성을 읽기 전용으로 변경, 수정이 불가능하게 만듦
    const user: {
      readonly name: string; // 읽기 전용 속성이 됨
      age: number;
      gender?: string; 
      // 옵셔널은 string | undefined와 똑같음
    } = {
      name: "john",
      age: 20,
    };
    
    // user.name = "james"; 변경하려고 하면 에러가 남
    console.log(user); // { name: 'john', age: 20 }
  • 배열이나 튜플의 경우는 배열 자체를 읽기 전용으로 만듦
  • 변수의 경우, 완전히 상수로 바꿈
    const arr: readonly number[] = [1, 2, 3];
      // arr[0] = 10; readonly 때문에 에러 남
      // arr.push(4); readonly 때문에 에러 남
      console.log(arr); // [ 1, 2, 3 ]

02. < 인덱스 시그니처 >

  • 객체의 속성이 같은 게 많을 때 사용
    const user: {
        [key: string]: string | number;
        // 동일한 속성일 경우, 인덱스 시그니처로 한 번에 표현
      } = {
        name: "john",
        gender: "male",
        address: "seoul",
        age: 20, // 추가하고 싶다면 위의 타입에 추가해야 함
      };

03. < 타입 별칭 (type alias) >

  • 객체의 타입을 지정할 때 사용
  • 기본 타입이 아닌 타입을 생성할 때 사용

1. 기본적인 타입 별칭

type ID = string | number;
// string, |, number는 타입 시스템에 있음
// string | number처럼 묶어서 사용하는 것은 타입 시스템에 없음
// 그래서 원하는 대로 조합해서 사용하는 것
let id: ID = "a";
id = 12345;

2. 객체 타입 별칭

type User = {
// 객체 형식으로 타입 별칭을 만들어서 사용 가능
    name: string;
    age: number;
  };

  const user2: { name: string; age: number } = {
    name: "john",
    age: 20,
  };
  // 코드 가독성이 좋아짐
  const user: User = {
    name: "john",
    age: 20,
  };

3. 함수 타입 별칭

type SumFunc = (n1: number, n2: number) => number;
// 함수 형식으로 만들어서 사용 가능
  const sum: SumFunc = function sum(n1, n2) {
    return n1 + n2;
  };

4. 제네릭 타입 별칭

  • 코드의 재사용성 증가
  • 근본적인 개념은 치환이다
  • 소문자여도 상관이 없지만, 관용적인 지정 방법으로 대문자
  • T가 제일 많이 사용 (Type의 약자)
  • U(Universal), K(Key), V(Value)
    type Car<U, T> = {
        name: string;
        color: U;
        // option: null | string | { giftcard: string };
        option: T;
      };
    
      const car: Car<string, null> = {
        name: "benz",
        color: "black",
        option: null,
      };
    
      const car2: Car<string, string> = {
        name: "benz",
        color: "black",
        option: "key",
      };
    
      const car3: Car<string, { giftcard: boolean }> = {
        name: "benz",
        color: "black",
        option: {
          giftcard: true,
        },
      };

5. 튜플 타입 별칭

type Point = [number, number];
  const point: Point = [10, 20]; // 좌표

6. 인터섹션 타입 별칭

type Nameable = {
    name?: string;
  };
  type Ageable = {
    age?: number;
  };
  type Person = Nameable & Ageable & { gender?: string };
  // 인터섹션 타입 &으로 병합하여 사용 가능

  const person: Person = {
    name: "john",
    age: 20,
    gender: "male",
  };

7. 리터럴 타입 별칭

  • 자동 완성이 가능해짐
type Direction = "LEFT" | "RIGHT" | "UP" | "DOWN";
  const direction: Direction = "RIGHT";

  type Gender = "femail" | "male" | "natural";
  const gender: Gender = "male";

8. 조건부 타입 별칭

  • T extends U ? X : Y
  • 고급 방법에 속함
type IsString<T> = T extends string ? "yes" : "no";
  const test1: IsString<string> = "yes";
  const test2: IsString<number> = "no";

9. 키 선택 타입 별칭

  • keyof 키워드 : 키만 추출해서 유니온으로 묶어줌
type Persons = {
    name: string;
    age: number;
    address: string;
  };

  type PersonKeys = keyof Persons; 
  // 키만 추출해서 유니온으로 묶어줌
  // "name" | "age" | "address"
  const key: PersonKeys = "address";

10. 인덱스 시그니처 타입 별칭

  • 객체의 속성을 동적으로 정할 수 있다.
  • 자동 속성 사용 불가
  • 자동 속성 사용하고 싶으면 고정 속성으로 추가해야 됨
  • 인덱스 시그니처고정 속성을 복합으로 사용 가능
type UseMap = {
    age: number; // 고정 속성
    [key: string]: string | number; // 인덱스 시그니처
  };

  let users: UseMap = {
    name: "john",
    age: 20,
    gender: "male",
    address: "seoul",
  };

04. < 인터페이스 >

  • 객체 타입을 지정할 때 사용하는 문법
  • 대부분 회사에서는 객체의 타입을 지정할 때 interface 사용
    그 외 커스텀 타입을 지정할 때 type 사용
  • 인터페이스는 객체, 함수(일급객체)만 타입을 지정할 수 있다

1. 문법

1.1. 기본 형식

interface 타입명 {: 키 타입}

interface User {
    name: string;
    age: number;
  }

  const user: User = {
    name: "john",
    age: 20,
  };

1.2. 옵셔널(?) 인터페이스

interface User {
    name: string;
    age?: number; // 옵셔널(?) 사용 가능
  }

  const user: User = {
    name: "john",
  };

1.3. readonly 인터페이스

  • 튜플이나 배열에서는 변수를 상수로 변환 (읽기 전용)
  • 객체에서는 속성을 읽기 전용으로 변환
interface User {
    name: string;
    readonly age: number; // 읽기 전용
  }

  const user: User = {
    name: "john",
    age: 20,
  };
  // user.age = 20 // 해당 속성에 동적 추가 시 에러 발생

1.4. 인덱스 시그니처 인터페이스

  • 객체의 동적 속성 정의 가능
interface User {
    name: string; // 고정 속성
    [key: string]: string; // 인덱스 시그니처
  }
  const user: User = {
    name: "james",
    gender: "male",
  };

1.5. 함수 타입 인터테이스

  • 실무에서 함수 타입을 인터페이스로 지정하는 일은 거의 없다
type SumFunc = (a: number, b: number) => number;
  const sum: SumFunc = (a, b) => a + b;

  interface IsSumFunc {
    (a: number, b: number): number;
    name: string; // 에러 발생 안 함
  // 함수 기본 속성에 arguments, length, name이 있기 때문
  // caller는 안 됨, 우리가 지정할 수 있는 값이 아님
  // 이 외의 값을 지정하면 에러 발생
  }
  const sum2: IsSumFunc = (a, b) => a + b;

2. 병합

  • 인터페이스는 자동 병합이 된다
  • 선언 병합(Declaration Merging)이라고도 함
// 인터페이스는 자동으로 합쳐짐
  interface User {
    name: string;
  }
  interface User {
    age: string;
  }
  
// 타입 별칭은 에러가 난다
  type TUser = {
   name: string;
  };
  type TUser = {
    age: number;
  };

3. 상속 (인터페이스 확장)

  • 인터페이스는 상속이 된다
    interface Shape {
        color: string;
      }
    
      interface Circle extends Shape { // 상속 가능
        radius: number;
        color: string;
      }
    
      const circle: Circle = {
        radius: 10,
        color: "red",
      };
      
    // type으로 상속처럼 보이게 작성할 수 있음
    // 하지만 상속이 아닌 인터섹션 타입을 이용한 것
    type Shape = {
        color: string;
      };
      type Circle = Shape & {
        radius: number;
      };
    
      const circle: Circle = {
        radius: 10,
        color: "red",
      };
  • 다중 상속 패턴
    interface Person {
        name: string;
        age: number;
      }
    
      const person: Person = {
        name: "john",
        age: 20,
      };
    
      interface Address {
        city: string;
        zipcode: string;
      }
    
    // 유지 보수나 가독성면에서 훨씬 더 이점을 가질 수 있다
      // Person, Address 처럼 나열해서 다중 상속
      interface Employee extends Person, Address {
        employeeId: string;
      }
    
      const employee: Employee = {
        name: "철수",
        age: 21,
        employeeId: "1234",
        city: "seoul",
        zipcode: "3111",
      };
  • 단축 메서드를 활용한 상속
    • 실무에서는 단축 메서드 많이 사용

      interface Animal {
          name: string;
          sound: () => void;
          // sound(): void (단축 메서드)
        }
      
        interface Pet extends Animal {
          play: () => void;
          // play(): void (단축 메서드)
        }
      
        const dog: Pet = {
          name: "뽀삐",
          sound: () => {
            console.log("멍멍");
          },
          // sound() {console.log("멍멍");} (단축 메서드)
          play: () => {
            console.log("놀기");
          },
          // play() {console.log("놀기");} (단축 메서드)
        };
      
        // 타입 가드를 한 번 사용 후 호출
        if (dog.play) dog.play();
  • 제네릭과 상속
    interface Container<U> {
        value: U;
      }
      
    // 제네릭은 치환한다고 생각하면 편하다.
    // 1) const box: Box<number, boolean>에서
    //    number가 T, boolean이 U로 넘어오고
    // 2) Container<U>에서 원하는 값을 들고와서
    // 3) interface Container<U>로 보낸다
      interface Box<T, U> extends Container<U> {
        label: string;
        scale?: T;
        inStock?: U;
      }
    
      const container: Container<number> = {
        value: 10,
      };
    
      const box: Box<number, boolean> = {
        label: "grid box",
        value: true,
        scale: 10,
      };

profile
첫 시작!

0개의 댓글