본문 바로가기
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
반응형