TS에서 private는 불완전한 private입니다.
그 이유를 살펴보면 ts의 private는 ts에서만 동작하기 때문입니다.
하지만 ts는 결국 js로 변환되고 변환된 js에서는 이제 더 이상 private속성은 없습니다.
js에서도 private를 유지하고 싶으시다면 #을 쓰세요
#은 내가 예상하지 못한 결과를 막아줄 수 있습니다.
Nest를 기준으로 설명코드를 작성하겠습니다.
ex)
class User {
@Exclude()
private _name: string;
set name(name: string) {
this._name = name;
}
get name() {
return this._name;
}
}
위의 코드를 역직렬화한다고 가정해보겠습니다.
const data = {
name: 'user1'
}
console.log(plainToInstance(User, data));
출력 결과는 어떻게 나올까요?
User { _name: user1 }
예상하신 결과가 잘 나오셨나요?
왜 이런 결과가 나왔을까요?
저는 처음에 이것이 버그인줄 알았습니다. 왜냐 @Excldue 데코레이터를 추가해주어 노출이 안되게 해주었는데 어째서 _name이 출력이 될까? 이것에 대한 이유를 찾았는데 그것은 바로 setter 때문이였습니다.
데코레이터들이 선언 되었을 때 그것은 metadata에 저장이 됩니다. class-transformer의 함수인
plainToInstance는 @Excldue 속성인 프로퍼티를 제외하여 _name를 Local this에 포함시키지 않았지만 값이 세팅될 때에 setter가 호출되며 _name에 값을 지정하게 되면서 Local this에 _name이 추가가 되어 결과적으로 _name이 출력되게 된것입니다.
이것이 어떻게 가능하냐!! private는 js에서는 private가 아니기 때문에 가능합니다.
반면 #을 이용한다면
class User {
#name: string;
set name(name: string) {
this.#name = name;
}
@Expose()
get name() {
return this.#name;
}
}
const data = {
name: 'user1'
}
console.log(plainToInstance(User, data)); // User { }
private속성이 js까지 잘 전달되었기 때문에 @Exclude() 데코레이터가 없더라도 출력이 되지 않습니다!
언제 # / private를 써야 할까에 대한 질문은 아래의 문서를 참고하시면 됩니다.
TypeScript