고급타입 #6

세나정·2023년 3월 7일
0

타입스크립트의 타입 시스템은 표현력 좋고, 쉽게 사용가능하고, 타입 제한과 관계 선언을 쉽고 간결하게, 타입을 명시하지 않아도 대부분 자동으로 추론

프로토타입, this 동적 연결, 함수 오버로딩, 항상 바뀌는 객체 등을 제대로 사용하려면 풍부한 타입 시스템과 다양한 타입 연산자 도구가 필요함

타입 간의 관계

- 서브타입과 슈퍼타입

예시

  • 배열은 객체의 서브타입이다.
  • 튜플은 배열의 서브타입이다.
  • 모든 것은 any의 서브타입이다.
  • never는 모든 것의 서브타입이다.
  • Animal을 상속받는 Bird 클래스가 있다면 Bird는 Animal의 서브 타입이다.

이 말은 곧

  • 객체를 사용해야 하는 곳에 배열도 사용할 수 있다.
  • 배열을 사용해야 하는 곳에 튜플도 사용할 수 있다.
  • any를 사용해야 하는 곳에 객체도 사용할 수 있다.
  • 어디에나 never를 사용할 수 있다.
  • Animal을 사용해야 하는 곳에 Bird도 사용할 수 있다.

이렇게 설명할 수 있다

이 그림처럼 반대로 말할 수도 있음
객체는 배열의 슈퍼타입이다~ 처럼 다 반대로 가능

- 가변성

A라는 타입이 B라는 다른 타입의 서브타입인지 아닌지 쉽게 판단할 수 있다.
number, string 등의 단순 타입은 그림 3-1의 흐름도로 확인하거나 자체적으로 쉽게 추론 가능 (예 : "number는 number | string 유니온에 포함되므로 number | string의 서브타입이다")
하지만 이런 것들은 매개변수화된 (제네릭) 타입 등 복합 타입에서는 이 문제가 더 복잡해짐

타입을 쉽게 설명하기 위한 약속

형태와 배열 가변성

응용 프로그램에 사용자를 묘사하는 형태가 있고 다음처럼 두 가지 타입으로 표현 한다고 침

만약 내가 어떤 회사에 인턴으로 취직하여서 사용자를 삭제하는 코드를 구현하는 업무를 맡았다면 다음처럼 구현할 수 있음

deleteUser는 { id ?: number, name : string } 타입의 객체를 받도록 정의 되었고 위에서 짠 { id : number, name : string } 이라는 existingUser 타입을 인수로 전달함

id 프로퍼티의 타입 (number)는 기대되는 타입 (number | undefined)의 서브타입이라는 사실에 주목
따라서, 전체 객체 { id : number, name : string }는 { id ?: number, name : string } 타입의 서브타입이므로 타입스크립트는 아무런 에러도 발생시키지 않음
(지우려는 애가 범위가 더 적음)

여기선 작은 문제가 있음 ExistingUser를 deleteUser로 전달해 삭제한 뒤에도 타입스크립트는 user의 id가 삭제된 사실을 모름

따라서 deleteUser(existingUser)로 id를 삭제한 다음 existingUser.id를 읽으면 타입스크립트는 여전히 existingUser.id가 number 타입일 것이라 생각함

어떤 객체를 슈퍼타입을 기대하는 곳에 사용한다는 것은 분명 안전하지 않음
완벽한 안전성을 추구하도록 설계되지 않고 완벽함 보다는 실제 실수를 잡는 것과 쉬운 사용이라는 두 가지 목표를 균형 있게 달성하는 것이 타입스크립트 타입 시스템의 목표

반대 방향 (슈퍼타입 사용이 아닌 서브타입이 필요한 곳에 할당)은 어떨까?
기존 사용자 (legacy user)라는 새로운 타입을 추가한 다음 이 타입의 사용자를 삭제 (타입스크립트를 도입하기 전에 동료 누군가가 작성해둔 코드에 새로운 타입을 추가하는 상황)

기대하는 슈퍼 타입의 프로퍼티를 포함하는 형태를 전달하면 타입스크립트는 에러를 발생시킴 슈퍼타입의 id는 string | number | undefined인데 반해
deleteUser는 id가 number | undefined 인 상황만을 처리할 수 있기 때문
(지우고 싶은 애가 범위가 더 많음)

타입스크립트는 어떤 형태를 요구할 때 건넬 수 있는 타입은, 요구되는 타입에 포함된 프로퍼티 각각에 대해 '<: 기대하는 타입'인 프로퍼티들을 가지고 있어야함
기대하는 프로퍼티 타입의 슈퍼타입인 프로퍼티가 있다면 건넬 수 없음

타입과 관련해 타입스크립트 형태 (객체와 클래스)는 그들의 프로퍼티 타입에 공변(covariant)한다고 말함
즉, 객체 B에 할당할 수 있는 객체 A가 있따면 '객체 A의 각 프로퍼티 <: B의 대응 프로퍼티' 라는 조건을 만족해야함

가변성의 네 종류


타입스크립트에서 모든 복합 타입의 멤버 (객체, 클래스, 배열, 함수, 반환 타입는 공변이며 함수 매개변수 타입만 예외적으로 반변

profile
기록, 꺼내 쓸 수 있는 즐거움

0개의 댓글