본문 바로가기
Frontend/TypeScript

[TypeScript] TypeScript 타입 시스템 이해 - 2

by 신림쥐 2024. 4. 14.
728x90
반응형

 

     


    타입 스크립트 원리 이해

    1. 타입 정의 기준
    2. 타입 관계 정의 기준
    3. 오류 검사 기준

     

    타입 호환성

    - 동일한 속성을 갖는 집합을 타입이라고 한다.

    - 어떤 타입을 다른 타른으로 변경해도 집합 안의 값인지 판단하는것을 타입 호환성이라고 한다.

    - 타입 호환성은 교집합 내에 판단한다. 

    예) 2, 0, -10, 0.123, Infenitiy

     

    슈퍼 타입, 서브 타입

    - 슈퍼 타입  : Down Cast(다운 캐스트)으로 변경될수 있는 타입

    - 서브 타입 : Down Cast(다운 캐스트)으로 변경될수 없는 타입

    *Down Cast(다운 캐스트)  : 슈퍼 타입의 값을 서브타입으로 변경하는것, 변경여부가 상황따라 다르다.

    *Up Cast(업 캐스트): 서브타입의 값을 슈퍼타입으로 변경하는 것, 무조건 변경이 가능하다.

    // unknow
    function unknowEx() {
      let a: unknown = 1;
      let b: unknown = "a";
      let c: unknown = true;
      let d: unknown = null;
      let e: unknown = undefined;
      let f: unknown = () => {};
    }
    
    // never
    function neverEx() {
      function func(): never {
        throw new Error();
      }
    
      let a: number = func();
      let b: string = func();
      let c: boolean = func();
      //   let d: never = 10; // error - up cast
      //   let e: never = "a"; // error - up cast
      //   let f: never = true; // error - up cast
    }
    
    // void
    function voidEx() {
      function func(): void {
        console.log("hi");
      }
    
      let a: void = undefined;
      // let b: number = undefined; // error - up cast
    }
    
    // any
    function anyEx() {
      let a: any;
      let b: number = 1;
      b = a; // any는 down cast에 영향을 받지 않는 특이 케이스
    
      let c: never;
      // c = a; // error - 단 never 제외
    }

     

     

    객체 타입 호환성

    - 프로퍼티가 일치하는지 검사한다.

    - 타입과 일치하지 않는 속성 값을 가진 객체는 슈퍼타입의 객체로 up cast가 불가능하다.

    type Info1 = { // super
      name: string;
      age: number;
    }
    
    type Info2 = { // sud : 추가 속성을 가지고 있다.
      name: string;
      age: number;
      address: string;
    };
    
    let p1: Info1 = {
      name: "kim",
      age: 20,
    };
    
    let p2: Info2 = {
      name: "kim",
      age: 20,
      address: "seoul",
    };
    
    p1 = p2;
    // p2 = p1; // error - 객체 속성에 없는 키 값을 가지고 있기때문에

     

     

    대수 타입

    - 여러개의 타입을 합성해서 만드는 타입을 말한다.

    - 합집합 타입과 교집합 타입이 존재한다.

    - 기본타입 교집합은 단일 타입에서는 사용하기 어렵고, 대부분 객체에서 사용된다.

    // 합집합 - union
    let a: string | number;
    a = 1;
    a = "a";
    
    let arr: (number | boolean)[] = [1, true];
    
    type User = {
      name: string;
      age: number;
    };
    type Animal = {
      name: string;
      kind: string;
    };
    type Union1 = User | Animal;
    let user1: Union1 = {
      name: "kim",
      age: 20,
    };
    let dog1: Union1 = {
      name: "choco",
      kind: "dog",
    };
    let cat1: Union1 = {
      name: "choco",
      age: 10,
      kind: "cat",
    };
    // let mouse: Union1 = {
    //   name: "choco", // error - 필수 속성이 없으면 오류
    // };
    
    // 교집합 - intersection
    let variable: number & string;
    // variable = 1; // error - variable는 nerver 타입이다.
    
    type intersection = User & Animal;
    // let user2: intersection = { // error
    //   name: "kim",
    //   age: 20,
    // };
    // let dog2 intersection = { // error
    //   name: "choco",
    //   kind: "dog",
    // };
    let cat2: intersection = {
      name: "choco",
      age: 10,
      kind: "cat",
    };

     

    타입 추론

    - 점진적 타입 시스템에서 가지는 특징

    - 타입을 직접 지정하지 않더라고 초기화 값으로 타입이 지정되는 것

    - 모든 타입에 타입이 추론되지는 않지만(특히  any) 타입 추론을 잘 사용하면 타입스크립트의 장점을 활용할 수 있다.

    // 타입 추론
    let l1 = 10;
    let l2 = "a";
    let l3 = {
      id: 1,
      name: "kim",
      profile: {
        address: "seoul",
      },
      url: ["www", "www2"],
    };
    
    let { id, name } = l3;
    
    let [a, b, c] = [1, 'a', true];
    
    function func (msg = 'hi') {
        return msg;
    }
    
    // 암묵적 any타입: 타입지정을 하지않고 초기화도 하지 않는 변수, 특정 구간내에서만 타입을 가지고 진화할 수 있다.
    let d; // any
    d =10; // number
    d.toFixed();
    
    d ='a'; // string
    d.split('a');
    
    // let, const
    let n1 = 10; // type : number
    const n2 = 10; // type : literal 10

     

     

    타입 단언

    - 타입 추론 상태에서  값을 나중에 가지게되는 변수인  경우, 값을 가지기 전에 타입 체크를 예외처리하는 것

    - 파라미터로 넣는 값이나 객체 값을 나중에 넣고 싶은 경우 사용한다.

    타입 단언 규칙

    - A가 B의 슈퍼타입이거나 서브타입 이어야한다.

    // 타입 단언
    type User = {
      name: string;
      age: number;
    };
    
    let person = {} as User;
    person.name = "kim";
    person.age = 20;
    
    let num1 = 10 as number;
    let num2 = 10 as never;
    let num3 = 10 as unknown;
    // let num4 = 10 as string; // error - 타입 교집합이 없는 타입이라 오류
    let num4 = 10 as unknown as string;

     

    Non null

    - typescript 컴파일러가 undifined 값이 아닐거라고 컴파일 하게 해주는 문법

    - 확실한 경우에만 사용

    // non null (!)
     type Post = {
      title: string;
      author?: string;
     }
    
    let post: Post = {
      title: '글1',
      author: '작성자1' // optional channing
    };
    const len: number = post.author!.length;

     

    타입 가드

    - 조건문 등을 사용하려 넓은 타입에서 좁은 타입으로 줄여가는 코드를 작성하는 것

    // 타입 좁히기
    type Person = {
      name: string;
      age: number;
    };
    
    function func(val: number | string | Date | null | Person) {
      if (typeof val === "number") {
        val.toFixed();
      } else if (typeof val === "string") {
        val.toLowerCase();
      } else if (val instanceof Date) {
        val.getTime();
      } else if (val && "age" in val) {
        console.log(val.name + val.age);
      }
    }

     

     

    서로소 유니온 타입

    - 교집합이 없는 타입으로만 만든 유니온 타입

    // 서로소 유니온 타입
    type Admin = {
      tag: "Admin";
      name: string;
      kickCount: number;
    };
    
    type Member = {
      tag: "Member";
      name: string;
      point: number;
    };
    
    type Guest = {
      tag: "Guest";
      name: string;
      visitCount: number;
    };
    
    type User = Admin | Member | Guest;
    
    function login(user: User) {
      // 안 좋은 예
      //   if('kickCount' in user){
      //     console.log(user.kickCount)
      //   }else if('point' in user){
      //     console.log(user.point);
      //   }else{
      //     console.log(user.visitCount);
      //   }
      // }
    
      // if (user.tag === "Admin") {
      //   console.log(user.kickCount);
      // } else if (user.tag === "Member") {
      //   console.log(user.point);
      // } else {
      //   console.log(user.visitCount);
      // }
      switch (user.tag) {
        case "Admin":
          console.log(user.kickCount);
          break;
        case "Member":
          console.log(user.point);
          break;
        case "Guest":
          console.log(user.visitCount);
          break;
        default:
          break;
      }
    }
    
    // 비동기 작업 처리 예
    type LoadTask = {
      state: "LOAD";
    };
    type FailedTask = {
      state: "FAILED";
      error: {
        message: string;
      };
    };
    type SuccessTask = {
      state: "SUCCESS";
      response: {
        data: string;
      };
    };
    // type AsyncTask = {
    //   state: "LOAD" | "FAILED" | "SUCCESS";
    //   error?: {
    //     message: string;
    //   };
    //   response?: {
    //     data: string;
    //   };
    // };
    type AsyncTask = LoadTask | FailedTask | SuccessTask;
    
    function processResult(task: AsyncTask) {
      switch (task.state) {
        case "LOAD":
          console.log("로딩중");
          break;
        case "FAILED":
          console.log("에러" + task.error.message);
          break;
        case "SUCCESS":
          console.log("성공" + task.response.data);
          break;
      }
    }
    
    const loading: AsyncTask = {
      state: "LOAD",
    };
    
    const failed: AsyncTask = {
      state: "FAILED",
      error: {
        message: "msg..",
      },
    };
    
    const success: AsyncTask = {
      state: "SUCCESS",
      response: {
        data: "data..",
      },
    };

     

     

    출처

    • 한 입 크기로 잘라먹는 타입스크립트(TypeScript)
    728x90
    반응형