#43 몽키 패치보다는 안전한 타입을 사용하기

2023. 4. 3.·🎨 프론트엔드 공부/JS & TS

이펙티브 타입스크립트 (댄 밴더캄 지음) 를 읽고 정리

📍요약

✅전역 변수 사용을 지양하고, DOM에 데이터를 저장하면 안된다 (UI와 데이터를 분리)

✅내장 타입에 데이터를 저장해야 하는 경우, 안전한 타입 접근법 중 하나를 사용한다

- 타입 보강

- 확장하는 인터페이스를 만들고 단언

✅보강의 모듈 영역 문제를 이해해야 한다

 

📍몽키 패치 (Monkey Patch)

✅런타임에 기존 코드를 동적으로 변경하는 것

예시

// 전역 객체에 임의의 프로퍼티 추가
document.monkey = 'Tamarin';
window.monkey = "Howler";
console.log(document.monkey); // 'Tamarin'
console.log(window.monkey); // "Howler"

// 내장 객체의 프로퍼티를 변경하는것은 안되는 듯..
Math.PI = 3;
console.log(Math.PI); // 3.141592653589793

 

📍객체와 클래스에 임의의 프로퍼티 추가 가능

✅자바스크립트는 유연하게 객체나 클래스에 임의의 프로퍼티를 추가할 수 있다

- 또한 DOM에 데이터를 자유롭게 추가할 수도 있다

// JavaScript Code

document.monkey = 'Tamarin';
window.monkey = "Howler";

const el = document.getElementById("colobus")!;
el.home = "tree";

 

✅심지어 내장 객체의 프로토타입에도 프로퍼티 추가 가능

// JavaScript Code

// 정규표현식 객체의 프로토타입에 임의의 프로퍼티 추가
RegExp.prototype.monkey = "Capuchin" // "Capuchin"

// 정규표현식 인스턴스에서 프로토타입 객체를 상속받기 때문에
// 임의의 프로퍼티 참조 가능
/123/.monkey // "Capuchin"

 

✅window 또는 DOM node에 데이터를 추가하면, 그 데이터는 전역 변수가 된다

- 이는 코드 내에서 불필요한 의존성을 갖게 하여 사이드 이펙트를 초래할 수 있다

 

✅타입스크립트의 경우, 타입 체커가 Document와 HTMLElement의 내장 속성을 알지만, 임의로 추가한 속성은 몰라서 에러를 발생

document.monkey = 'Tamarin';
      // ~~~~~~ Property 'monkey' does not exist on type 'Document'
window.monkey = "Howler";
      // 타입 에러 : Window & typeof globalThis 에 monkey 프로퍼티 없음

const el = document.getElementById("colobus")!;
el.home = "tree";
    // 타입 에러 : HTMLElement 에 home 프로퍼티가 없음

 

에러를 해결하려면 any 단언문을 사용할 수 있지만... 언어 서비스 기능을 이용할 수 없다

// any 단언문
(document as any).monkey = 'Tamarin';  // OK

// any 때문에 언어 서비스 기능 비활성화
(document as any).monky = 'Tamarin';  // Also OK, 오타 감지 기능 비활성화
(document as any).monkey = /Tamarin/;  // Also OK, 타입 감지 기능 비활성화

 

2가지 대안이 존재한다

 

 

📍1. Type 보강(Augmentation)

✅타입 보강을 통해 기존의 Document 인터페이스를 확장

interface Document {
  monkey: string;
}

document.monkey = 'Tamarin';  // OK
document.monke = 'Tamarin'; // 타입에러 : 오타 감지 기능 활성화

 

✅장점

1. 타입 안정성

2. 언어 서비스 기능 활성화 (오타, 주석, 자동완성 등)

3. 몽키 패치가 어떤 부분에 적용됐는지 기록 남음

 

esmodule 을 지원하게 하려면 global 선언을 추가해야 한다

export {};
declare global {
  interface Document {
    monkey: string;
  }
}
document.monkey = 'Tamarin';  // OK

 

✅하지만, 보강은 전역적으로 사용되기 때문에, 이 부분을 분리할 수 없다는 문제가 있다

 

더 정확하게 사용하려면...

📍2. 구체적인 타입 단언문

Document 인터페이스를 확장하는 MonkeyDocument 인터페이스를 만들고 document에 단언

interface MonkeyDocument extends Document {
  monkey: string;
}

(document as MonkeyDocument).monkey = 'Macaque';

 

✅장점

⭐모듈 영역 문제를 해결 (import 하는 곳에서만 사용할 수 있다)

'🎨 프론트엔드 공부/JS & TS' 카테고리의 다른 글
  • [Web API] 서비스 워커 (service worker)
  • #45 devDependencies에 TypeScript와 @types 추가하기
  • JavaScript 실행시간 측정 : performance.now()
  • #42 모르는 타입의 값에는 any 대신 unknown을 사용하기
지식물원
지식물원
지식이 자라는 식물원!
  • 지식물원
    지식물원
    지식물원
  • 전체
    오늘
    어제
    • 분류 전체보기 (510)
      • 🎨 프론트엔드 공부 (247)
        • JS & TS (86)
        • HTML & CSS (22)
        • React & Next (49)
        • Vue & Nuxt (22)
        • 기타 (68)
      • 🤓 기술 학습 & 공부 기록 (116)
        • Node.js (0)
        • Python (37)
        • 백엔드 (0)
        • 딥러닝 (1)
        • 컴퓨터 일반 (72)
        • 개발 인프라 (6)
      • 👨‍💻 프로젝트 경험 (6)
        • Work (0)
        • Toy (6)
      • ⚙️ 개발 팁 & 노하우 (21)
        • 프론트엔드 (6)
        • 기타 (15)
      • ☕️ 커리어 & 인터뷰 준비 (88)
        • 코딩 테스트 (88)
      • 📰 기술 트렌드 & 생각 정리 (4)
      • 📚 기타 (25)
        • 마케팅 (15)
        • 비개발서적 (10)
  • 블로그 메뉴

    • 태그
  • 링크

  • 공지사항

    • 모바일 접속 시 코드 하이라이팅 깨질 때
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
지식물원
#43 몽키 패치보다는 안전한 타입을 사용하기
상단으로

티스토리툴바