최근에는 스터디 팀원들과 1~2주 간격으로 자바스크립트로 토이 프로젝트를 만들고 서로 코드리뷰하는 시간을 가지고 있고 이번 주차에는 우테코에서 제공하는 숫자 야구 게임을 진행하기로 하였다.
조금 더 특별하게 타입스크립트에 익숙해보고자 타입스크립트도 도입하였다. 숫자 야구 게임은 복잡한 구조를 가진 프로젝트가 아니여서 어떻게 하면 코드를 깔끔하게 작성할지에 대한 고민을 많이 했던 것 같다. 그래서 고민했던 내용들을 저장해두면 좋을 것 같아 개인적으로 정리해보았다.
조건문의 경우에는 캡슐화하는 것이 좋다. 아래의 경우에는 단순하게 조건문 내부에 작성하여도 의도를 알 수 있지만 조금 더 복잡해지는 조건문의 경우에는 함수로 빼두면 함수명만으로도 의도를 파악할 수 있기 때문에 좀더 좋은 코드가 될 수 있다고 생각한다.
// 변경 전
function getComputerInputNumbers(): string {
const numbers = new Set();
while (numbers.size < INPUT_NUMBER.LENGTH)) {
numbers.add(getRandomNumber(INPUT_NUMBER.MIN, INPUT_NUMBER.MAX));
}
return [...numbers].join('');
}
// 변경 후
function isLessThanInputMaxLength(size: number) {
return size < INPUT_NUMBER.LENGTH;
}
function getComputerInputNumbers(): string {
const numbers = new Set();
while (isLessThanInputMaxLength(numbers.size)) {
numbers.add(getRandomNumber(INPUT_NUMBER.MIN, INPUT_NUMBER.MAX));
}
return [...numbers].join('');
}
메서드나 함수의 경우에는 결국 의도를 드러내기 위해서는 하나의 역할만 하도록 구현해야 하기 때문에 '함수는 하나의 역할만'와도 관련된 내용인 것 같다.
이름을 짓는데 시간을 많이 쓰자!
Property 'xxx' has no initializer and is not definitely assigned in the constructor. ts(2564)
다음의 코드와 같이 클래스 속성으로 email을 지정해줬지만 생성자에서 이니셜라이즈 해주지 않은 경우에 오류가 발생하는 것을 볼 수 있다.
class UserAccount {
name: string;
email: string;
address: string | undefined;
constructor(name: string) {
this.name = name;
// Note that this.email is not set
}
}
생성자 내부에서 이니셜라이즈해주면 쉽게 해결이 가능하겠지만 상황에 따라서는 생성자 내부에 정의할 필요가 없는 경우도 존재하기 때문에 다른 방식으로 해결해보려고 한다.
tsconfig.json에 설정을 수정하는 방법이다.
"strictPropertyInitialization": false
strictPropertyInitialization를 true로 설정한다면, 클래스 속성이 선언되었지만 생성자에서 설정되지 않은 경우 TypeScript에서 오류가 발생한다.
Non-null assertion operator를 사용하는 방법이다.
class UserAccount {
name: string;
email!: string;
constructor(name: string) {
this.name = name;
// Note that this.email is not set
}
}
접미에 붙는!
를 사용하면 null 또는 undefined가 아니라고 단언해주게 되면서 경고가 표시되지 않는다.
하지만 이 방법은 나중에 잠재적인 문제를 발생시킬 수 있기 때문에 추천하지 않으며 차라리 vertical bar (|)을 사용하는 union types 방법을 추천한다.
class UserAccount {
name: string;
email: string | undefined;
constructor(name: string) {
this.name = name;
// Note that this.email is not set
}
}