[이펙티브 타입스크립트] 객체 래퍼 타입 피하기
반응형
자바스크립트와 기본형 타입
자바스크립트의 기본형 값들에 대한 7가지 타입(number, boolean, string, undefined, null, symbol, bigint)
기본형들은 불변(immutable)이며 메서드를 가지지 않는다.
하지만 'birdview'.charAt(3) 는 문제없이 실행되며, 이는 기본형 값인 ‘birdview’가 메서드를 가지고 있는 것처럼 보인다. 하지만..
- chatAt은 string의 메서드가 아니다.
- chatAt을 사용할 때 내부동작이 발생 (기본형 string에는 메서드가 없지만, 객체 String 타입이 정의)
래퍼 객체 (Wrapper Object)
레퍼 객체는 총 3가지(Number, String, Boolean)이 있다.
let name = 'birdview';
console.log(name.length); // 8
console.log(name.charAt(0)); // "b"
- name은 문자열이다 ⇒ 원시타입
- name.length 혹은 name.charAt 처럼 프로퍼티를 참고하려고 할 때
- name = new String(’birdview')
- 다음과 같이 래퍼 객체 String 일시적으로 실행되어, name을 객체화 시킨다.
- 이로 인해, name은 객체화되어 String의 프로퍼티를 참고 할 수 있게 된다.
- 즉, 원시타입을 객체화 시켜주는 객체형 데이터 타입을 래퍼객체 라고 한다.
몽키패치란(monkey Patch)?
일반적으로 런타임 중인 프로그램 메모리의 소스 내용을 직접 바꾸는 것이다.
ex) prototype 객체의 특정 메소드를 수정하는 행위
💡 원래 게릴라 패치 였는데 (guerrilla patch) 발음의 유사성 때문에 사람들이 고릴라 패치(gorilla patch) 라고 쓰기 시작했다. 하지만 "고릴라" 라고 하면 좀 무섭고 위험하게 들리므로 (CEO 에게) 고릴라보다 덩치가 작은 원숭이 패치로 부르게 됐다고 한다. (monkey Patch)
예제
const originalCharAt = String.prototype.charAt;
String.prototype.charAt = function(pos) {
console.log(this, typeof this, pos);
return originalCharAt.call(this, pos + 1)
};
console.log(
'birdview'.charAt(0)
);
→ this는 원시 타입 string이 아니라 객체 타입 string이다
원시 타입과 객체 타입은 다르다.
"hello" === new String("hello"); // false
new String("hello") === new String("hello") // false
프로퍼티를 호출나서는, wrapping한 객체를 버린다.
let name = 'birdview';
name.length = 20; // new String(name).length = 20;
// 래핑한 name 객체 메모리 clear
name.charAt = function() { // new String(name).charAt = function() { // .. }
console.log('another charAt');
}
// 래핑한 name 객체 메모리 clear
console.log(name.length); // 8
// 래핑한 name 객체 메모리 clear
console.log(name.charAt(0)); // "b"
원시 타입 - 객체 타입
- number → Number
- boolean → Boolean
- string → String
- symbol → Symbol
- bigint → BigInt
null, undefined 에는 객체 레퍼가 없다
타입스크립트는 원시형과 객체 레퍼 타입을 별도로 모델링 한다.
string 사용시 유의해야한다. string ≠ String
function getStringLen(foo: String) {
return foo.length;
}
getStringLen("hello"); // 정상
getStringLen(new String("hello")); // 정상
// 런타입 값은 객체가 아니라 원시형
const s: String = 'birdview'; // 정상
const n: Number = 93; // 정상
const b: Boolean = true; // 정상
// ------------------------------------------------
// 잘못된 케이스
function isGreeting(phrase: String) {
return [
'hello',
'good day'
].includes(phrase); // 에러
}
- Array.prototype.includes의 첫번째 인자는 string 타입을 받는다.
- string은 String에 할당할 수 있지만, String은 string에 할당할 수 없다.
- but, 기본형 타입을 객체 래퍼에 할당하는 구문은 오해하기 쉽고, 그렇게 할 필요가 없다!
- (참고) 대부분의 라이브러리, ts가 제공하는 타입 선언은 전부 원시 타입으로 되어 있다.
BigInt와 Symbol 타입
typeof BigInt(1234) // "bigint"
typeof Symbol('sym') // "symbol"
이것들은 BigInt와 Symbol 값이다. 타입이 아니다.
요약
- 객체 래퍼 타입이 어떻게 동작하는지 이해해야한다. 이를 직접 사용하거나 인스턴스를 생성하는 것을 피해야 한다.
- 타입스크립트 객체 래퍼타입은 지양하고, 대신 기본형 타입을 사용하자
- String 대신 string
- Number 대신 number
- Boolean 대신 boolean
- Symbol 대신 symbol
- BigInt 대신 bigint
반응형
'프로그래밍 > Typescript' 카테고리의 다른 글
[이펙티브 타입스크립트] 타입 공간과 값 공간의 심벌 구분하기 (0) | 2022.06.05 |
---|---|
[이펙티브 타입스크립트] #4 구조적 타이핑에 익숙해지기 (0) | 2022.06.05 |
[TypeScript] e.target.target 타입 에러가 나는 이유 ts(2339) (0) | 2022.06.04 |
댓글
이 글 공유하기
다른 글
-
[이펙티브 타입스크립트] 타입 공간과 값 공간의 심벌 구분하기
[이펙티브 타입스크립트] 타입 공간과 값 공간의 심벌 구분하기
2022.06.05 -
[이펙티브 타입스크립트] #4 구조적 타이핑에 익숙해지기
[이펙티브 타입스크립트] #4 구조적 타이핑에 익숙해지기
2022.06.05 -
[TypeScript] e.target.target 타입 에러가 나는 이유 ts(2339)
[TypeScript] e.target.target 타입 에러가 나는 이유 ts(2339)
2022.06.04