질문 배경
TypeScript에서 비공개 필드는 처음에 private 수정자를 통해 도입되었고, ECMAScript 2021부터는 JavaScript에서 # 기호를 통해 진정한 비공개 필드가 지원됩니다. 주요 목표는 데이터 캡슐화로, 클래스의 내부 세부 정보를 외부에서 접근하지 못하도록 보호하는 것입니다.
문제점
TypeScript의 private 수정자는 컴파일 단계에서만 비공개성을 보장하지만, 컴파일된 JavaScript에서는 이러한 필드가 객체의 속성에 직접 접근하여 여전히 접근 가능할 수 있습니다. 이는 객체의 상태가 의도치 않게 변경되는 결과를 초래할 수 있습니다. ES 비공개 필드(#)는 클래스 외부에서는 JS 런타임 수준에서도 완전히 접근할 수 없으며, 이는 데이터의 진정한 보호를 보장합니다.
해결책
TypeScript는 두 가지 접근 방식을 모두 지원합니다. 둘 중에서 선택할 때는 필요한 보호 수준과 JS 버전과의 호환성 제한을 고려하십시오.
코드 예시:
class Example { private hidden: number; #trulyHidden: string; constructor() { this.hidden = 42; this.#trulyHidden = 'secret'; } getHidden() { return this.hidden; } getTrulyHidden() { return this.#trulyHidden; } } const x = new Example(); // x.hidden — TS에서는 오류, 그러나 JS에서는 x['hidden']을 통해 동작할 수 있음 // x.#trulyHidden — JS에서도 문법 오류
주요 특징:
private는 TypeScript의 컴파일 단계에서만 비공개성을 보장함#field는 JavaScript 실행 단계에서 진정한 비공개성을 제공함#를 사용하는 것은 최신 JS 지원이 필요함 (ES2021+)TypeScript 클래스의 private 필드에 JS에서 직접 접근할 수 있나요?
네, 컴파일 단계에서만 비공개성이 구현되므로 가능합니다. 원래 JS에서는 해당 필드가 객체의 일반적인 속성이 됩니다. 예:
class A { private x = 1; } const a = new A(); console.log((a as any)["x"]); // 1
인터페이스나 type을 사용해 # 비공개 필드를 설명할 수 있나요?
아니요, #private 필드는 클래스의 구현의 일부일 뿐, 인터페이스나 타입에서 설명될 수 없으며 클래스 외부에서 사용할 수 없습니다. 인터페이스는 공개 멤버만 설명합니다.
#로 선언된 비공개 필드를 상속할 수 있나요?
아니요, 이러한 필드는 상속된 클래스에서도 전혀 접근할 수 없습니다. 오직 해당 클래스만이 접근할 수 있습니다:
class Parent { #foo = 123; } class Child extends Parent { // this.#foo = 444; // 오류 }
private를 사용하는 것은 직접 접근 시 취약점으로 이어질 수 있음비밀번호를 저장하는 프로젝트에서 User 클래스에 private password 필드가 사용되었습니다. 개발자 중 한 명이 디버깅을 위해 우연히 user['password']를 통해 접근하게 되고, 필드가 외부 모듈에 의해 변경됩니다.
장점:
단점:
개발자가 ES 비공식 필드 #password를 사용하게 되었습니다. 이제 인덱싱이나 상속된 클래스에서 필드에 접근하려는 시도가 실패하며, 외부 라이브러리와 도구를 사용하더라도 데이터 보안이 확보되었습니다.
장점:
단점: