TypeScript 배우기4

Parker.Park·2022년 8월 2일
0

TypeScript

목록 보기
4/8

타입스크립트 시작하기, Inflearn


주말에 TypeScript 강의를 조금 들으면서 정리를 못한 것이 많다. 이어서 해보겠다. 처음 타입스크립트 강의를 들을 때 정리해야 할것들이 이렇게 많을줄 몰랐다. TIL에서 정리하는 것이 괜찮은 방식인지 고민하게 되었다. 블로깅할 때는 편할지는 몰라도 나중에 찾을 때는 좀 난해질수 있다는 생각이 들었다.

type 호환성(Type Compatibility)

TypeScript의 특징중 하나라고 생각한다. A타입이 B타입을 사용할 수 있는데, A타입이 B타입을 포함할 수 있기 때문이다. 이것은 TypeScript가 컴파일시 호환되는지 않되는지 판단하기 때문이라고 한다.
예시를 보면서 정리해 보자.

function f1(a: number | string, b: number) {
  const v1: number = a; //Error!
  const v2: number | string = b;

  console.log(v1, v2);
}

f1()
// error TS2322: 
// Type 'string | number' is not assignable to type 'number'.

위 예시와 같이 parmeter a는 number 와 string이 올 수 있지만, v1은 number만 타입을 지정하였기때문에 에러가 발생하였다. 즉 a타입집합이 v1타입집합보다 크기 때문이다.
반대로 v2타입집합이 매개변수 b를 포함할 수 있기때문에 에러가 발생하지 않았다.

structural typing

위에서 TypeScript는 type 호환성이 가능하다고 하였는데 이유는 structural typing을 기반으로 하기 때문이다. structural typing은 "Duck Typing", "Structural Type System"이라고도 한다. 서로다른 타입이라고하여도 타입 호환성이 맞다면 허용하는 것이라고 한다. 강의에서는 structural typing이라고 하고, Docs에서는 structural subtyping이라고도 말한다.(typing과 subtyping이 같은 의미인거 같으나 정확히는 구분이 안간다.) 대조적으로 nominal subtyping이라고 있다. Java에서 사용한다고 하는데, 호환이 가능하다 할지라도 반드시 할당 된 타입만 따르는 것이라고 한다. JavaScript와 같은 비교적 자유로운 언어를 기반으로 TypeScript가 나왔기 때문이라고 한다. 예시를 보자.

interface Dog {
  name: string;
  numFeet: number;
}

interface Bird {
  name: string;
  numFeet: number;
}

let a: Dog = { name: "abc", numFeet: 4 };
let b: Bird = a;

예시와 같이 Dog형식으로 할당된 a가 Bird타입인 b에 할당이 가능하다. 다른 타입이라도 구조적으로 같기 때문에 가능하다.
인터페이스인 경우 속성이 많을수록 타입집합이 적어질 수밖에 없다. 그 만큼 할당 가능한 타입이 적어지기 때문이다. 다른예시를 보자.

interface Dog {
  name: string;
  numFeet?: number; //
}

interface Bird {
  name: string;
  numFeet: number;
}

let a = { name: "abc" };
let b: Dog = a; 

let c: Bird = a;
// error TS2741:
// Property 'numFeet' is missing in type '{ name: string; }' 
// but required in type 'Bird'.

인터페이스 Dog에서 numFeet이라는 프로퍼티는 옵셔널이기 때문에 a객체를 할당 가능하였지만, Bird는 더 조건이 많기 때문에 할당에서 에러가 발생한다. 이게 좀 헷갈렸는데 다른 예를 추가적으로 보자.

interface Pet {
  name: string;
}

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

let a1 = { name: "a1", age: 3 };
let a2 = { name: "a2", city: "home" };

let b1: Pet = a1;
let b2: Pet = a2;

let b3: Cat = a1;

let b4: Cat = a2; 
//error TS2741: Property 'age' is missing in type 
//'{ name: string; city: string; }' but required in type 'Cat'.

위 예시를 보면 a1은 Pet, Cat 타입 모든 변수에 할당이 가능하다. Pet타입에 없는 속성에 대해서 호환을 하기 때문일 것이다. 하지만 변수 a2의 경우 Pet타입 변수에는 할당 가능하였으나, Cat타입 변수에는 에러가 발생하였다. city라는 속성이 필요하기 때문이다. 하지만 변수 타입에 직접 객체를 만든다면 에러가 발생할 것이다.

let b5: Pet = { name: "a3", age: 1 }; 
//error TS2322: 
//Type '{ name: string; age: number; }' is not assignable to type 'Pet'.

그 이유는 프로그래머가 정의된 타입에 리터럴로 직접 할당할 경우 오타를 발생할 확률이 더 높기 때문에 타입스크립트에서 에러를 발생시키는 거라고 한다.

마치면서

type에 호환성이라는 것이 꽤 생소하게 들렸다. 대부분은 순조롭게 이해했는데 function type에 대해서는 이해가 안가는 부분이 있어서 좀더 보고 업데이트하리라 맘먹는다.

참조

[Type Compatibility, TypeScript Docs, 2022년08월03일 접속]
https://www.typescriptlang.org/docs/handbook/type-compatibility.html#handbook-content

[[Typescript] Type Compatibility 타입 호환성, Velog, 2022년08월03일 접속]
https://velog.io/@eunn/Typescript-Type-Compatibility-%ED%83%80%EC%9E%85-%ED%98%B8%ED%99%98%EC%84%B1

[Structural vs Nominal Subtyping 그리고 TypeScript, Velog, 2022년08월04일 접속]
https://velog.io/@vlwkaos/Structural-vs-Nominal-Subtyping-%EA%B7%B8%EB%A6%AC%EA%B3%A0-TypeScript

[TypeScript의 기본 (Structural Type System)goldentrash·2020년 10월 27일, Velog, 2022년08월04일 접속]
https://velog.io/@goldentrash/TypeScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95

[인프런강의 : 타입스크립트 시작하기]

profile
개발자준비중

0개의 댓글