Typescript Duck Typing (덕타이핑)

후훗♫·2021년 2월 28일
15

타입스크립트의 인터페이스에 대한 글을 읽다가 Duck Typing에 대해 알게되었다.

먼저 코드로 개념을 이해해보자.

interface People {
    talk(): void;
    whoAmI: string;
}

class Human implements People {
    whoAmI = "human"
    talk = () => {
        console.log(`say ${this.whoAmI} : 말할 수 있어요`);
    }
}

class Robot {
    whoAmI = "robot"
    talk  = () => {
        console.log(`say ${this.whoAmI} : 말할 수 있어요`);
    }
}

const humanInstance = new Human(); 
const robotInstance = new Robot();

function startTalk(people: People): void {
    people.talk();
}

startTalk(humanInstance); // --- 1) "say human : 말할 수 있어요"
startTalk(robotInstance); // --- 2) "say robot : 말할 수 있어요"

(위의 코드는 Typesrcipt playground에서도 확인 가능하다!)

먼저 1번의 함수호출을 보면,
humanInstancestartTalk를 실행하는 것은 에러가 예상되지 않는다.

Class HumanInterface People을 상속받아 생성되었고,
humanInstance Class HumanInstance이기 때문이다.

즉, 함수 startTalk파라미터 people이 정의된 타입대로 호출되었다.
(파라미터 peopleinterface People로 정의되어 있다!)

그럼 2번의 함수호출을 보자.
파라미터로 들어간 robotInstanceInterface People로 정의되어 있지 않다.
따라서 error가 발생할 것 같았다.

이 시점에서 타입스크립트의 Duct Typing 개념이 적용된다.

Class RobotClass Human이 정의된 대로 변수 whoAmI, Method talk 모두 가지고 있다.

Interface People은 아니지만,
Interface People이 가지고 있는 property를 모두 가지고있으므로 타입체크를 통과하게 된다.

타입스크립트의 interface 문서를 살펴보자.

타입스크립트 공식 홈페이지 interface 관련 문서의 첫 문장이다.

One of TypeScript’s core principles is that type checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural subtyping”.
In TypeScript, interfaces fill the role of naming these types, and are a powerful way of defining contracts within your code as well as contracts with code outside of your project.

Typescript에서의 타입체크는 shape에 집중하고 있고,
이를 duck typing 혹은 structural subtyping이라 정의한다고 설명한다.

Duck Typing을 잠시 정리해보면,

위키백과는 Duck Typing을 아래와 같이 정의한다.

컴퓨터 프로그래밍 분야에서 덕 타이핑(duck typing)은 동적 타이핑의 한 종류로,
객체의 변수 및 메소드의 집합이 객체의 타입을 결정하는 것을 말한다.
클래스 상속이나 인터페이스 구현으로 타입을 구분하는 대신,
덕 타이핑은 객체가 어떤 타입에 걸맞은 변수와 메소드를 지니면 객체를 해당 타입에 속하는 것으로 간주한다.
만약 어떤 새가 오리처럼 걷고, 헤엄치고, 꽥꽥거리는 소리를 낸다면 나는 그 새를 오리라고 부를 것이다.

타입스크립트의 Duct Typing 특성때문에,
내가 예시로 만든 2번의 case와 같이
정의된 타입이 아니더라도 정의된 타입과 같은 Shape를 가지고 있다면
타입체크에서는 에러가 나오지 않는다.

정적인 TypeScript, 동적인 Duck Typing?!

이 글을 쓰게 된 이유이기도하다.
타입스크립트의 duck typing을 검색하면 마이구미님의 블로그가 검색된다.

덕 타이핑에 대해 조금 인지하고 있는 상태에서 본인은 다음과 같이 생각했다.
위에서 언급했듯이, 타입스크립트는 결국 정적으로 타입을 검사하고 싶어 사용하는 것이 아닌가?
그런데 덕 타이핑은 어떻게 보면 동적인 성향이 강하지 않나? 라는 의문이 들었다.

자바스크립트는 동적타입의 언어이다.

자바스크립트로 처음 프로그래밍으로 접한 나는
동적 타이핑이 얼마나 어색하고, 당황스러운 부분인지 사실 잘 몰랐다....🤔
(지금도 잘은 모르겠다....ㅎㅎ)

내가 만든 코드에 어떤 값이 들어오는지 모르는 상황이
정적 타입의 언어로 프로그래밍을 시작한 분들에게는 굉장히 당황스러운 것이라 한다.

유연한 언어라는 점이 장점이라고 언급되지만,
예측할 수 없는 에러를 발생시킨다는 단점이 항상 수반된다.

그래서 타입스크립트가 자바스크립트의 정적 타이핑을 지원하는 것으로 유명해졌다.

그런데 마이구미님의 의문처럼,
정적 타이핑을 지원하는 타입스크립트는 Duck Typing의 특성이 있고,
Duck Typing은 동적 타이핑의 한 종류라고 말하니 좀 혼란스러웠다.

다시 마이구미님의 글에서 보면 아래와 같이 정리되어있다.

본인의 의문은 결국 타입 검사 측면다형성 측면의 관점을 분리해서 생각하지 않아서 나온 생각이였다.
덕 타이핑은 다형성 측면의 관점으로 볼 수 있다.

(타입검사, 다형성 관점을 분리한다는 것이 좀 이해하기 어려웠다..ㅠ)

타입(data의 형태)을 컴파일 단계에서 결정하면 정적 타이핑이라 하고,
런타임 단계에서 결정하면 동적 타이핑이라 한다.

타입스크립트는 타입 검사런타임 단계가 아닌 컴파일 단계에서 진행한다.
즉, 타입 검사 측면에서 타입스크립트를 보면 타입스크립트는 정적 타이핑이다.라고 말할 수 있다.

다형성 측면의 관점에서도 타입스크립트를 살펴보자.

먼저 OOP의 다형성 정의부터 살펴보면 은근.. 아니, 매우매우매우 철학적이다..ㅋㅋㅋ

  • 하나의 메소드나 클래스가 있을 때 이것들이 다양한 방법으로 동작하는 것을 의미한다.
  • 하나의 객체가 여러 개의 자료형 타입을 가질 수 있다.

위의 정의대로만 보면 다형성은 "여러 가지 형태를 가지고 있다"라고 이해하면 된다.
그러나 다형성 역시 정적 다형성, 동적 다형성으로 구분할 수 있다...😭
(이 점을 몰랐기 때문에 다형성관점에서 dock Typing을 연결하는 것이 쉽지 않았던 것 같다.)

  • 정적 다형성은 컴파일 타임 바인딩을 의미하며, 동적 다형성은 런타임 바인딩을 의미합니다.
  • 보통 객체 지향 언어에서 정적 다형성을 overloading이라고 하며, 동적 다형성을 overriding
    이라고 부릅니다.
  • 정적 다형성(혹은 overloading)은 동일한 함수 이름을 가지더라도 해당 함수가 가지는 파라
    미터들의 개수, 타입, 순서가 다를 경우 컴파일러가 다른 함수로써 인식 하는 것을 의미합니다.
  • 동적 다형성(overriding)은 동일한 함수 이름과 파라미터 특성을 지닌, 상속 관계에
    있는 클래스들의 멤버 함수에 대해서 외형적으로 호출되는 타입에 상관없이 실제 생성된 객체
    의 함수가 호출되도록 처리 되는 특성을 의미합니다.
    ...
    다형성의 이런 특성(=동적)에 의해 객체 지향 프로그래밍에서는 ‘동일한 인터페이스의 여러 객체,
    동일한 객체의 여러 인터페이스’를 갖는 것이 가능합니다.
    *출처

(overloading, overriding에 대한 가장 쉬운 설명은 생활코딩👍에서 가장 잘하고 있는듯 하다!)

어떤 객체의 형태가 컴파일 단계에서 결정되면 정적 다형성,
런타임 단계에서 결정되면 동적 다형성이라 한다.
(여기서 말하는 객체는 class 내의 method라고 생각하면 이해하기 쉽다.)

타입스크립트는 컴파일 단계에서 실제로 지정된 Type인지 아닌지를 판단하지 않는다.
대신 런타입 단계에서 지정된 Type이 가지고 있는 변수와 method가 있는지 판단하고,
없다면 에러가 발생된다.

즉, 타입스크립트는 런타임 단계에서 객체가 어떤 형태를 지니고 있는 판단하는 동적 다형성
혹은 덕타이핑의 특성을 지니고 있다.


최종적으로 정리하면,
타입스크립트의 정적타이핑타입검사 측면에서 해석한 결과이고,
타입스크립트의 동적타이핑인 Duck Typing은 다형성의 측면에서 해석한 결과이다.

그래서 타입스크립트를 정적, 동적 이라는 상반된 개념 모두 연관지을 수 있었던 것...!!! 같다!


하.. 배울게 너무나 많다...... 😭

[참고]

profile
꾸준히, 끄적끄적 해볼게요 :)

0개의 댓글