ts-for-jsdev
  • 자바스크립트 개발자를 위한 타입스크립트
  • 들어가며
  • 01 타입스크립트 소개
    • 1.0 들어가며
    • 1.1 정적 타입 분석
    • 1.2 왜 타입스크립트인가
    • 1.3 타입스크립트의 구성요소
    • 1.4 타입스크립트의 역사
  • 02 ECMAScript
    • 2.0 ECMAScript
    • 2.1 블록 수준 스코프
      • 2.1.1 let을 이용한 선언
      • 2.2.2 const를 이용한 선언
      • 2.2.3 스코프 베스트 프랙티스
    • 2.2 객체와 배열
      • 2.2.1 비구조화 할당
      • 2.2.2 나머지 연산자와 전개 연산자
      • 2.2.3 객체 리터럴 변경사항
    • 2.3 함수
      • 2.3.1 기본 매개변수
      • 2.3.2 화살표 함수
    • 2.4 템플릿 리터럴
      • 2.4.1 멀티라인 문자열
      • 2.4.2 문자열 치환
    • 2.5 원소 순회
      • 2.5.1 forEach 메소드
      • 2.5.2 for-of 문법
      • 2.5.3 이터레이터 프로토콜
      • 2.5.4 이터러블 프로토콜
    • 2.6 비동기 처리
      • 2.6.1 프로미스
      • 2.6.2 Async / Await
    • 2.7 맺으며
  • 03 타입스크립트 기초 문법
    • 3.0 타입스크립트 기초 문법
    • 3.1 기본 타입
    • 3.2 배열과 튜플
    • 3.3 객체
    • 3.4 타입 별칭
    • 3.5 함수
    • 3.6 제너릭
    • 3.7 유니온 타입
    • 3.8 인터섹션 타입
    • 3.9 열거형
  • 04 인터페이스와 클래스
    • 4.0 들어가며
    • 4.1 인터페이스 기초
    • 4.2 색인 가능 타입
    • 4.3 인터페이스 확장
    • 4.4 클래스
    • 4.5 클래스 확장
    • 4.6 클래스 심화
      • 4.6.1 스태틱 멤버
      • 4.6.2 접근 제어자
      • 4.6.3 접근자
      • 4.6.4 추상 클래스
    • 4.7 인터페이스와 클래스의 관계
    • 4.8 맺으며
  • 05 타입의 호환성
    • 5.0 들어가며
    • 5.1 기본 타입의 호환성
    • 5.2 객체 타입의 호환성
    • 5.3 함수 타입의 호환성
    • 5.4 클래스의 호환성
    • 5.5 제너릭의 호환성
    • 5.6 열거형의 호환성
    • 5.7 맺으며
  • 06 타입 시스템 심화
    • 6.0 들어가며
    • 6.1 타입 좁히기
    • 6.2 타입 추론
    • 6.3 타입 단언
    • 6.4 집합으로서의 타입
    • 6.5 서로소 유니온 타입
    • 6.6 맺으며
  • 07 고급 타입
    • 들어가며 (7월 2일 공개)
  • 08 모듈과 네임스페이스
    • 들어가며 (7월 16일 공개)
  • 09 실제 프로젝트에서 사용하기
    • 들어가며 (7월 30일 공개)
  • 10 유용한 라이브러리 소개
    • 들어가며 (8월 13일 공개)
    • 맺으며
  • 부록 II : 자바스크립트 언어 생태계
    • ECMAScript 언어 표준과 TC39
    • TC39 프로세스
    • 실제 예시 - Array.prototype.includes
    • 타입스크립트와 ECMAScript
Powered by GitBook
On this page
  • 매개변수 수가 같은 경우
  • 매개변수 수가 다른 경우
  1. 05 타입의 호환성

5.3 함수 타입의 호환성

타입스크립트가 함수 타입 간의 호환성을 판단하는 법에 대해 다룬다.

매개변수 수가 같은 경우

함수 타입 간의 호환성을 판단하려 할 때, 가장 간단한 경우는 두 함수의 매개변수의 갯수가 같은 경우다. 이 때, 할당을 받는 함수의 타입을 Target, 할당하려는 함수의 타입을 Source라 하자.

let source: Source;
const target: Target = source;

위 코드가 허용되는지, 즉 Target이 Source에 할당 가능한지를 보기 위해선 다음 두 질문에 답해야 한다.

  • Target과 Source의 모든 매개변수 타입에 대해, Source의 매개변수 타입이 Target의 매개변수 타입에 할당 가능한가?

  • Target의 반환 타입이 Source의 반환 타입에 할당 가능한가?

두 질문에 대한 답이 모두 “예”라면, Target은 Source에 할당 가능하다.

직관적으로는, 선택 매개변수와 필수 매개변수는 호환성을 판단할 때 다르게 취급되는 게 맞아 보인다. 하지만 타입스크립트에선 매개변수가 선택 매개변수인지 필수 매개변수인지는 함수 타입의 호환성 판단에 아무런 영향을 주지 않는다.

할당 가능한 경우

먼저 할당 가능한 경우를 살펴보자.

type Sum = (sumFirst: number, sumSecond: number) => number;
type Multiply = (mulFirst: number, mulSecond: number) => number;
  • 모든 매개변수 타입은 number로, 서로 할당 가능하다.

  • Multiply의 반환 타입인 number는 Sum의 반환 타입인 number에 할당 가능하다.

따라서 Sum은 Multiply에 할당 가능하다.

const sum: Sum (sumFirst: number, sumSecond: number) => {
  return sumFirst + sumSecond;
};
const multiply: Multiply = sum; // ok

할당 불가능한 경우

다음으로는 할당이 불가능한 예제를 살펴보자.

interface Animal { animalProp: string };
interface Dog extends Animal { dogProp: number };

let f = (animal: Animal) => animal.animalProp;
let g = (dog: Dog) => { doSomething(dog.dogProp) };

f = g;
  • 할당받는 함수의 매개변수 타입 Animal은 할당하는 함수의 매개변수 타입 Dog에 할당 불가능하다.

만족되지 않는 기준이 있으므로 g는 f에 할당할 수 없다.

이 때, 이 기준을 만족해야 하는 이유는 뭘까? 즉, f의 매개변수 타입인 Animal 이 g의 매개변수 타입인 Dog에 할당 불가능하면 왜 g를 f에 할당하지 못해야 할까?

해당 할당을 허용하는 경우를 생각해보자. 만약 f = g 의 할당을 허용한다면 다음과 같이 Animal 타입의 인자를 넘길 수 있을 것이다.

const cat: Animal = { animalProp: 'cute' };
f(cat); // 컴파일러는 통과 시켜 줌

하지만 g 는 인자가 Dog 일 것이라 가정하고, Dog 에만 존재하는 속성 dogProp 에 접근하고 있다. 따라서 런타임 에러가 발생할 수 있다. 이런 상황을 막기 위해 타입스크립트는 이 경우 f = g 와 같은 할당을 금지한다.

매개변수 수가 다른 경우

매개변수 수가 같은 두 함수의 호환성을 비교하는 법에 대해 살펴봤다. 이번엔 매개변수의 수가 다른 경우엔 상황이 어떻게 달라지는지를 다음 두 함수 타입을 통해 살펴보자.

type Login = (id: string) => Response<Data>;
type LoginWithToken = (id: string, token: string) => Response<Data>;

할당하는 함수의 매개변수 수가 더 많은 경우

아래 코드에서 할당하는 함수인 loginWithToken은 할당받는 함수 login에 비해 token: string 이라는 매개변수를 추가적으로 갖고 있다.

const loginWithToken: LoginWithToken = (id: string, token: string) => { /* ... */ };
const login: Login = loginWithToken;

이런 경우는 할당이 불가능하다. 만약 이 할당을 허용한다고 생각해보자. 프로그래머는 이 함수를 다음과 같은 식으로 호출할 것이다.

login('myId');

이는 loginWithToken 함수를 token 인자 없이 호출하는 셈이다. loginWithToken 함수 내에서 token을 string 타입이라 생각하고 사용했다면, string이 필요한 자리에 undefined 값이 넘어와서 런타임 에러가 발생할 것이다. 따라서 이런 할당은 허용되지 않는다.

할당받는 함수의 매개변수 수가 더 많은 경우

아래 코드에서 할당하는 함수인 login은 할당받는 함수인 loginWithToken에 비해 매개변수 수가 하나 모자라다.

const login: Login = (id: string) => { /* ... */ };
const loginWithToken: LoginWithToken = login;

이런 경우, 초과 매개변수는 무시된다. 그리고 매개변수 수가 같을 때와 동일한 알고리즘으로 호환성을 판단한다. 위의 경우, 초과 매개변수인 token: string 을 제외하고 첫 번째 매개변수는 동일한 타입을 가지므로 할당은 문제 없이 진행된다.

Previous5.2 객체 타입의 호환성Next5.4 클래스의 호환성

Last updated 6 years ago