타입스크립트 덕 타이핑 (구조적 타이핑)

Sheryl Yun·2022년 10월 4일
0

타입스크립트

목록 보기
3/11
post-thumbnail

(이 짤을 쓰는 날이 오다니.. 여담으로 현재 석촌호수에 러버덕이 8년 만에 돌아왔다고 한다🐤)


오늘은 타입스크립트의 덕 타이핑(구조적 타이핑)에 대해 알아보고자 한다. 최근 오픈 카톡(테오의 프론트엔드)에서 끊임없이 언급이 쏟아지는 주제이기도 하고, 타입스크립트의 특징을 좀 더 잘 알기 위해 조사해볼 주제라는 생각이 들어서였다.

구조적 타이핑이란 뭘까?

코드 구조 관점에서 타입이 서로 호환되는지의 여부를 판단하는 것

그러면 왜 구조적 타이핑을 덕 타이핑이라고 할까? 검색하다가 구조적 타이핑을 대략적으로 얘기한 다음 글을 발견했다.

typescript의 기초 원리는 타입 체크 시 해당 변수가 가지고 있는 '모양'에 집중하는 것이다. 이것을 duck typing 또는 structural typing이라고 부른다.
예를 들어 dictionary 또는 map이라고 불리는 structure는 안에 key, value가 몇 쌍이 있던 똑같은 모양으로 보는 것이다.

대충 알 것 같으면서도 개념이 애매모호했다. 추측해보면 for문이 몇 번 반복되든 2N, 3N이라고 보지 않고 무조건 O(N)이라고 보는 시간 복잡도 개념과 비슷한 걸까?

다른 블로그에서 예시 코드를 발견했다.

// 타입 정의
interface People {
    talk(): void; // 메서드
    whoAmI: string; // 상태
}

// People 타입을 상속하여 Human 클래스 선언
class Human implements People { // 타입을 상속할 때는 'implements'
    whoAmI = "human"
    talk = () => {
        console.log(`say ${this.whoAmI} : 말할 수 있음`);
    }
}

// People 타입 상속 없이 Robot 클래스 선언
class Robot { // 타입 상속을 따로 하지 않음
    whoAmI = "robot"
    talk  = () => {
        console.log(`say ${this.whoAmI} : 말할 수 없음`);
    }
}

// 인스턴스 생성
const humanInstance = new Human(); 
const robotInstance = new Robot();

// People 타입을 가지는 인자를 받아서 talk 메서드 호출
function startTalk(people: People): void {
    people.talk();
}

startTalk(humanInstance); // say human : 말할 수 있음
startTalk(robotInstance); // say robot : 말할 수 없음

Robot 클래스의 경우 Human과 달리 People 타입을 따로 상속하지 않았는데도 People 타입의 인자를 갖는 startTalk 함수에 인스턴스를 넣어 호출할 때 에러가 발생하지 않았다. 이것을 '덕 타이핑' 또는 '구조적 타이핑'이라고 부른다고 한다.

덕 타이핑은 한 마디로 '모양(생김새)이 같으면 같은 타입으로 간주하겠다'는 뜻이다. Robot 클래스의 경우 Human 클래스처럼 whoAmI 상태와 talk 메서드를 모두 갖고 있으므로 People 타입이 아니어도 People 타입의 '모양'을 갖고 있으면 그대로 타입 체크를 통과하는 것이다.

이걸 표현하는 유명한 문장은 다음과 같다.

"If it walks like a duck and it quacks like a duck, then it must be a duck"
만약 어떤 새가 오리처럼 걷고, 헤엄치고, 꽥꽥거리는 소리를 낸다면 나는 그 새를 오리라고 부를 것이다.

정의된 타입 중에 같은 모양이 있다면 해당 인스턴스는 그 타입을 상속했다고 보고 타입 검사를 통과하게 된다.

정적이냐 동적이냐

덕 타이핑이 어려운 이유는 위에서 말한 개념 그 자체보다 타입스크립트가 '정적 언어'인데 덕 타이핑은 '동적이라는 특징' 때문인 것 같다. 하지만 이것은 분명히 다른 영역에서 따져야 할 개념이다.

타입스크립트가 정적인 언어라는 부분은 '타입 검사' 영역과 관련되어 있다.
타입을 결정하는 시점이 컴파일 타임이냐, 런타임이냐에 따라
컴파일 시점에 미리 타입을 결정하는 타입스크립트와 런타임 때 동적으로 타입을 결정하는 자바스크립트로 나뉘는 것이다.

그러면 덕 타이핑이 관련되어 있는 영역은 어디일까?
바로 객체 지향 프로그래밍의 '다형성' 개념이라고 한다.
따지고 들어가면 상당히 철학적인 개념인데 간단히 설명하면,

하나의 메소드나 클래스가 있을 때 이것들이 다양한 방법으로 동작하는 것을 의미한다.

좀 더 자세히 얘기하면 다음과 같이 정적 다형성과 동적 다형성으로 또 구분된다.
이 중에 덕 타이핑이 해당되는 파트는 동적 다형성으로 보인다.

정적 다형성은 컴파일 시점 바인딩을 의미하며, 동적 다형성은 런타임 시점 바인딩
객체 지향 언어에서 정적 다형성은 overloading, 동적 다형성은 overriding

정적 다형성(overloading)은 동일한 함수 이름을 가지더라도 해당 함수가 가지는 파라
미터들의 개수, 타입, 순서가 다를 경우 컴파일러가 다른 함수로 인식

동적 다형성(overriding)은 동일한 함수 이름과 파라미터 특성을 지닌, 상속 관계에
있는 클래스들의 멤버 함수에 대해서 외형적으로 호출되는 타입에 상관없이 실제 생성된 객체의 함수가 호출되도록 처리되는 특성

결론

... 다형성의 이러한 동적인 특성에 의해 객체 지향 프로그래밍에서는 ‘동일한 인터페이스의 여러 객체, 동일한 객체의 여러 인터페이스’를 갖는 것이 가능하다.

이러한 특성으로, 타입스크립트에선 덕 타이핑(구조적 타이핑)이 가능하다고 한다.
실제 코드로 다루는 부분이 중요하기 때문에 이론은 여기까지만 하려고 한다.

실제에서 적용할 부분은 '타입과 속성이 똑같은 클래스의 경우 따로 해당 타입을 implements로 상속할 필요가 없다'는 것이다. (코드 줄어드는 거 너무 좋아..) 근데 이 개념이 같은 파일에 타입과 클래스가 모두 있을 때만 해당하는지는 직접 써 봐야 알 것 같다.

참고

Typescript Duck Typing (덕타이핑)
덕 타이핑(Duck Typing)이란? :: 마이구미

profile
데이터 분석가 준비 중입니다 (티스토리에 기록: https://cherylog.tistory.com/)

0개의 댓글