this의 타입
this의 값은 함수를 어떻게 호출했는지에 따라 달라지는데 이는 JAvaScript 코드를 이해하기 어렵게 만드는 고질적인 문제 중 하나입니다. (따라서 많은 개발팀에선 클래스 메서드를 제외한 다른 모든 곳에서 this 사용을 금한다고 합니다.)
this가 자주 문제를 일으키는 원인은 할당 방법에 있습니다.
메서드를 호출할 때 this는 점 왼쪽의 값을 갖는다는 것이 일반적인 원칙입니다.
let x = {
a() {
return this
}
}
x.a() // a()의 바디 안에서 this는 객체 x
하지만 호출이 일어나기 전 어느 시점에서 a를 다시 할당하면 결과가 달라집니다.
let a = x.a
a() // 이제 a의 바디 안에서 this는 정의되지 않은 상태
아래처럼 날짜의 타입을 포매팅하는 유틸리티 함수가 있다고 가정해 봅니다.
function beautifulDate(){
return ${ this.getDate() } /${this.getMonth()} /${ this.getFullYear() }
}
그리고 이 API는 함수 매개변수가 무엇인지 모르는 아주 오래전에 설계됐다고 가정합니다.
이 버전의 beautifulDate를 호출하려면 this로 한정할 Date를 제공해야 합니다.
fancyDate.call(new Date) // "1/1/2006"로 평가
만약 Date를 한정하는 것을 잊어버리면, 런타임 예외가 발생합니다.
beautifulDate() // 처리되지 않은 TypeError: this.getDate는 함수가 아님
this는 어떻게 선언하느냐가 아니라 함수를 어떻게 호출하느냐에 영향을 받습니다.
다행히도 TypeScript는 이 문제를 잘 처리해 줍니다.
함수에서 this를 사용할 때, 기대하는 this 타입을 함수의 첫 번째 매개변수로 선언하면, 함수 안에 등장하는 모든 this가 의도한 this가 됨을 TypeScript가 보장해주기 때문입니다.
함수 시그니처에 사용한 this는 예약어이므로 다른 매개변수와 완전히 다른 방식으로 처리됩니다.
function beautifulDate(this: Date) {
return ${ this.getDate() } / ${ this.getMonth() } / ${ this.getFullYear() }
}
이렇게 수정한 beautifulDate를 호출하면 아래와 같은 일이 벌어집니다.
beautifulDate.call(new Date) // "2/21/2007"으로 평가함
beautifulDate() // error TS2684: void 타입의 'this'를 메서드에 속한 'Date' 타입의 'this에 할당할 수 없음
TypeScript에 많은 정보를 제공한 덕분에 런타임 에러 대신 컴파일 타임에 경고를 하게 됐습니다.
TSC 플래그: noImplicitThis
tsconfig.json에서 noImplicitThis를 활성화하면, 함수에서 항상 this 타입을 명시적으로 설정하도록 강제할 수 있습니다.
단, noImplicitThis는 클래스와 객체의 함수에는 this를 지정하라고 강제하지 않습니다.
'👶 TypeScript' 카테고리의 다른 글
제너레이터 함수 (0) | 2023.01.11 |
---|---|
TypeScript 실행 (0) | 2023.01.11 |
call, apply, bind (0) | 2023.01.11 |
나머지 매개변수 (0) | 2023.01.10 |
선택적 매개변수와 기본 매개변수 (0) | 2023.01.10 |