Vite 프로젝트를 생성한다.
DOM 요소를 null 로 인식
DOM 에 대한 타입 지정 필요
사용자들과 상호작용할 수 있는 DOM 요소(HTMLDivElement), 마우스 이벤트(MouseEvent) 타입을 지정해주어야 한다.
그리고 이 요소들이 없을 때 null 로 인식될 수 있는 값 (빈 값이 될 수 있는 값)들을 tpescript로 다 잡아내서 꼼꼼하게 체크
개발자의 입장에서는 번거롭고 불편한 작업이지만 조금 더 안전한 결과물을 만들어낼 수 있다는 장정이 있다.
▶ 입력창에 render
const Calculator = {
render() {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(9999);
}
}
}
Calculator.render();
▶ 값 0으로 설정
const Calculator = {
value: 0,
render() {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(this.value);
}
}
}
Calculator.render();
▶ 클릭 시 입력창에 값 표기
1. Click 시 버튼 정보 콘솔에 찍기
function onClickButton() {
const buttonContainerEl = document.querySelector('.contents');
// ? (선택적 프로퍼티 | 옵셔널 체이닝) : https://developer-talk.tistory.com/193
buttonContainerEl?.addEventListener('click', console.log);
}
const Calculator = {
value: 0,
render() {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(this.value);
}
},
initEvent() {
onClickButton();
}
}
Calculator.render();
Calculator.initEvent();
1-2. Click 시 버튼 값 콘솔에 찍기
function onClickButton() {
const buttonContainerEl = document.querySelector('.contents');
buttonContainerEl?.addEventListener('click', function({ target }) {
console.log((target as HTMLButtonElement).innerText);
});
}
const Calculator = {
value: 0,
render() {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(this.value);
}
},
initEvent() {
onClickButton();
}
}
Calculator.render();
Calculator.initEvent();
2. initEvent 정리 + this 에러
const Calculator = {
value: 0,
render() {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(this.value);
}
},
reset() {
this.value = 0;
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
buttonContainerEl?.addEventListener('click', function ({ target }) {
const buttonText = (target as HTMLButtonElement).innerText;
// console.log((target as HTMLButtonElement).innerText);
if (buttonText === 'AC') {
// 여기서 this는 Event target 을 가리킴
// 이 함수호 바인딩된 this가 지정되지 않았기 때문에, typescript에서 이 this는 any 에 가까움
this.reset(); // --> this Error : 'this'에는 형식 주석이 없으므로 암시적으로 'any' 형식이 포함됩니다.ts(2683)
main.ts(39, 50): 'this'의 외부 값은 이 컨테이너에서 섀도 처리됩니다.
} else {
}
});
}
}
Calculator.render();
Calculator.initEvent();
3. this 에러
const Calculator = {
value: 0,
render() {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(this.value);
}
},
reset() {
this.value = 0;
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
// buttonContainerEl?.addEventListener('click', function ({ target }) {
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
// console.log((target as HTMLButtonElement).innerText);
if (buttonText === 'AC') {
// 여기서 this는 Event target 을 가리킴
// 이 함수호 바인딩된 this가 지정되지 않았기 때문에, typescript에서 이 this는 any 에 가까움
/* [ 해결 방법 ]
* 1. tsconfig.json 파일의 compilerOtions 에 "noImplicitThis" : false 로 설정한다.
noImplicitThis 는 this를 더 까다롭게 본다는 설정 ( 기본값 true)
이 방법은 권장하지 않음
2. 화살표 함수로 변경
화살표 함수의 this는 일반함수의 this와 동작이 다르기 때문에 Error가 생기지 X
*/
this.reset();
} else {
}
});
}
}
Calculator.render();
Calculator.initEvent();
inputNumber 전달하기
const Calculator = {
value: 0,
render() {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(this.value);
}
},
reset() {
this.value = 0;
},
operator(inputNumber: number) {
alert(inputNumber);
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
// buttonContainerEl?.addEventListener('click', function ({ target }) {
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
// console.log((target as HTMLButtonElement).innerText);
if (buttonText === 'AC') {
// 여기서 this는 Event target 을 가리킴
// 이 함수호 바인딩된 this가 지정되지 않았기 때문에, typescript에서 이 this는 any 에 가까움
/* [ 해결 방법 ]
* 1. tsconfig.json 파일의 compilerOtions 에 "noImplicitThis" : false 로 설정한다.
noImplicitThis 는 this를 더 까다롭게 본다는 설정 ( 기본값 true)
이 방법은 권장하지 않음
2. 화살표 함수로 변경
화살표 함수의 this는 일반함수의 this와 동작이 다르기 때문에 Error가 생기지 X
*/
this.reset();
} else {
// this.operator(buttonText); // --> buttonText 는 innerText. 그리고 innerText 는 string ( Number형으로 변환 필요 )
this.operator(Number(buttonText));
}
});
}
}
Calculator.render();
Calculator.initEvent();
inputNumber 그리기 ( 1자리 )
문제 > 숫자가 3자리까지 입력되도록 하고 싶은데, 이 코드는 한 자리만 그려짐
const Calculator = {
value: 0, // 초기값
// render(inputValue: string | number) {
render(inputValue?: string | number) {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(inputValue || this.value); // inputValue가 없을 경우 초기값 넣기
}
},
reset() {
this.value = 0;
},
operator(inputNumber: number) {
// alert(inputNumber);
this.render(inputNumber)
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
// buttonContainerEl?.addEventListener('click', function ({ target }) {
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
// console.log((target as HTMLButtonElement).innerText);
if (buttonText === 'AC') {
// 여기서 this는 Event target 을 가리킴
// 이 함수호 바인딩된 this가 지정되지 않았기 때문에, typescript에서 이 this는 any 에 가까움
/* [ 해결 방법 ]
* 1. tsconfig.json 파일의 compilerOtions 에 "noImplicitThis" : false 로 설정한다.
noImplicitThis 는 this를 더 까다롭게 본다는 설정 ( 기본값 true)
이 방법은 권장하지 않음
2. 화살표 함수로 변경
화살표 함수의 this는 일반함수의 this와 동작이 다르기 때문에 Error가 생기지 X
*/
this.reset();
} else {
// this.operator(buttonText); // --> buttonText 는 innerText. 그리고 innerText 는 string ( Number형으로 변환 필요 )
this.operator(Number(buttonText));
}
});
}
}
Calculator.render();
Calculator.initEvent();
inputNumber 그리기 ( 3자리 )
import "./style.css";
const VALID_NUMBER_OF_DIGITS = 3;
const BASE_DIGIT = 10;
const validateNumberLength = (value: string | number) => {
return String(value).length < VALID_NUMBER_OF_DIGITS;
}
const Calculator = {
value: 0, // 초기값
// render(inputValue: string | number) {
render(inputValue?: string | number) {
const resultEl = < HTMLDivElement > document.querySelector('#result');
if (resultEl) {
resultEl.innerText = String(inputValue || this.value); // inputValue가 없을 경우 초기값 넣기
}
},
reset() {
this.value = 0;
},
operator(inputNumber: number) {
// alert(inputNumber);
this.render(inputNumber)
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
// buttonContainerEl?.addEventListener('click', function ({ target }) {
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
// console.log((target as HTMLButtonElement).innerText);
if (buttonText === 'AC') {
// 여기서 this는 Event target 을 가리킴
// 이 함수호 바인딩된 this가 지정되지 않았기 때문에, typescript에서 이 this는 any 에 가까움
/* [ 해결 방법 ]
* 1. tsconfig.json 파일의 compilerOtions 에 "noImplicitThis" : false 로 설정한다.
noImplicitThis 는 this를 더 까다롭게 본다는 설정 ( 기본값 true)
이 방법은 권장하지 않음
2. 화살표 함수로 변경
화살표 함수의 this는 일반함수의 this와 동작이 다르기 때문에 Error가 생기지 X
*/
this.reset();
} else {
// this.operator(buttonText); // --> buttonText 는 innerText. 그리고 innerText 는 string ( Number형으로 변환 필요 )
this.operator(Number(buttonText));
}
});
}
}
Calculator.render();
Calculator.initEvent();
STEP 1
import "./style.css";
const VALID_NUMBER_OF_DIGITS = 3;
const BASE_DIGIT = 10;
const validateNumberLength = (value: string | number) => {
return String(value).length < VALID_NUMBER_OF_DIGITS;
}
const Calculator = {
value: 0, // 초기값
// render(inputValue: string | number) {
render(inputValue?: string | number) {
const resultEl = < HTMLDivElement > document.querySelector('#result');
const prevValue = Number(resultEl.innerText);
if (resultEl) {
// resultEl.innerText = String(prevValue + inputValue || this.value); // inputValue가 없을 경우 초기값 넣기
resultEl.innerText = isNaN(prevValue) ? String(inputValue) : String(prevValue);
}
},
reset() {
this.value = 0;
},
operator(inputNumber: number) {
// alert(inputNumber);
this.render(inputNumber)
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
// buttonContainerEl?.addEventListener('click', function ({ target }) {
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
// console.log((target as HTMLButtonElement).innerText);
if (buttonText === 'AC') {
// 여기서 this는 Event target 을 가리킴
// 이 함수호 바인딩된 this가 지정되지 않았기 때문에, typescript에서 이 this는 any 에 가까움
/* [ 해결 방법 ]
* 1. tsconfig.json 파일의 compilerOtions 에 "noImplicitThis" : false 로 설정한다.
noImplicitThis 는 this를 더 까다롭게 본다는 설정 ( 기본값 true)
이 방법은 권장하지 않음
2. 화살표 함수로 변경
화살표 함수의 this는 일반함수의 this와 동작이 다르기 때문에 Error가 생기지 X
*/
this.reset();
} else {
// this.operator(buttonText); // --> buttonText 는 innerText. 그리고 innerText 는 string ( Number형으로 변환 필요 )
this.operator(Number(buttonText));
}
});
}
}
Calculator.render();
Calculator.initEvent();
STEP 2
import "./style.css";
const VALID_NUMBER_OF_DIGITS = 3;
const BASE_DIGIT = 10;
const INIT_VALUE = 0;
const validateNumberLength = (value: string | number) => {
return String(value).length < VALID_NUMBER_OF_DIGITS;
}
const Calculator = {
value: 0, // 초기값
render(inputValue?: string | number) {
const resultEl = < HTMLDivElement > document.querySelector('#result');
const prevValue = resultEl.innerText;
if (resultEl) {
resultEl.innerText = Number(prevValue) === 0 ? String(inputValue) : String(prevValue + inputValue)
}
},
reset() {
this.value = 0;
},
operator(inputNumber: number) {
this.render(inputNumber)
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
if (buttonText === 'AC') {
this.reset();
} else {
this.render(Number(buttonText));
}
});
}
}
Calculator.render(INIT_VALUE);
Calculator.initEvent();
조금 더 간결하게 isZero
import "./style.css";
const VALID_NUMBER_OF_DIGITS = 3;
const BASE_DIGIT = 10;
const INIT_VALUE = 0;
const validateNumberLength = (value: string | number) => {
return String(value).length < VALID_NUMBER_OF_DIGITS;
}
const isZero = (value: string) => Number(value) === 0;
const Calculator = {
value: 0, // 초기값
render(inputValue?: string | number) {
const resultEl = < HTMLDivElement > document.querySelector('#result');
const prevValue = resultEl.innerText;
if (resultEl) {
resultEl.innerText = isZero(prevValue) ? String(inputValue) : String(prevValue + inputValue)
}
},
reset() {
this.value = 0;
},
operator(inputNumber: number) {
this.render(inputNumber)
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
if (buttonText === 'AC') {
this.reset();
} else {
this.render(Number(buttonText));
}
});
}
}
Calculator.render(INIT_VALUE);
Calculator.initEvent();
import "./style.css";
const VALID_NUMBER_OF_DIGITS = 3;
const BASE_DIGIT = 10;
const INIT_VALUE = 0;
const validateNumberLength = (value: string | number) => { // 3자리 여부 검사
return String(value).length < VALID_NUMBER_OF_DIGITS;
}
const isZero = (value: string) => Number(value) === 0; // 0 인지 검사
const Calculator = {
value: 0, // 초기값
render(inputValue?: string | number) {
const resultEl = < HTMLDivElement > document.querySelector('#result');
const prevValue = resultEl.innerText;
if (!validateNumberLength(prevValue)) { // 3자리 입력 제한하기
alert('3자리 이상의 숫자를 입력할 수 없습니다.');
return;
}
if (resultEl) {
resultEl.innerText = isZero(prevValue) ? String(inputValue) : String(prevValue + inputValue)
}
},
reset() {
this.value = 0;
},
operator(inputNumber: number) {
this.render(inputNumber)
},
initEvent() {
const buttonContainerEl = document.querySelector('.contents');
buttonContainerEl?.addEventListener('click', ({ target }) => {
const buttonText = (target as HTMLButtonElement).innerText;
if (buttonText === 'AC') {
this.reset();
} else {
this.render(Number(buttonText));
}
});
}
}
Calculator.render(INIT_VALUE);
Calculator.initEvent();