지난 포스팅에서 JS + CRA로 관련용어 기능을 완성했었다. 그래서 이제 자바스크립트 파일에 타입을 입혀 타입스크립트로 변환을 해야했고 어제 좀 만져봤다. 근데 아무래도 개념강의도 듣고 했지만 아직 타이핑이 익숙하지 않아서 시간이 좀 걸렸고 완성했다.
이게 완성한 자바스크립트 파일이다. (+ Create React App 사용)
이번 모각코 시간에는 우선 CRA + TS로 바꿔보고자 타이핑을 입혀봤고, 그 과정에서 에러도 여러개 발생하였다.
결과적으로는 잘 되어서, 각각 어떻게 타이핑을 해줬는지를 포스팅해보려고 한다.
기본적으로
const TermRelated = () => {
(...)
}
여기에서 (...) 안에 앞으로 포스팅할 내용들이 들어간다는 점을 인지하고 보면 좋겠다.
1. 메인 함수에서 useState
interface ITerms {
id: number;
text: string;
}
const [relatedTerms, setRelatedTerms] = useState<ITerms[]>([]);
const [inputTerm, setInputTerm] = useState("");
const [id, setId] = useState(1);
기존 JS에서 TS로 변경을 해주려면(보통 이렇게는 안한다. 처음 만들 때 애초에 타입스크립트로 만들고 보통 여기에서 바꿔야된다면 타입만 제거한 뒤 자바스크립트로 바꿔주는 방식이다) useState의 대상이 되는 relatedTerms의 타입에 대한 정의가 필요했다.
그래서, interface ITemrs로 relatedTerms 내부에 들어갈 id와 text를 각각 number, string으로 정의를 해주었다. useState에서 <ITerms[]> 형태로 들어간 것은, ITerms 자체가 배열 형태를 띠고있기 때문이라고 보면 될 것 같다. 나는 그렇게 이해를 했다.
그리고 useState 내부의 괄호 안에 다시 대괄호를 넣은 것은,

이러한 형태로 값이 저장되게끔 하기 위해서이다. id, text를 묶은 중괄호들을 대괄호로 묶기 위해서 useState 내부에 대괄호를 넣은 것이라고 보면 되곘다.
이외에 inputTerm이나 Id는 기존 자바스크립트 파일과 같으므로 넘어가겠다. (id는, 초기 id값을 1부터 시작하게 하기 위해서 useState 내부에 1을 넣었다.)
2. onChange와 onClick
const onChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
const lastIdx = e.target.value.length - 1;
if (e.target.value[lastIdx] === ",") return;
setInputTerm(e.target.value);
};
const onClick = () => {
for (let i = 0; i < relatedTerms.length; i++) {
if (relatedTerms[i].text === trimmedInputTerm) {
setInputTerm("");
alert("중복");
return;
}
}
const termsArray = relatedTerms.concat({
id: id,
text: inputTerm.trim().replace(/[^ㄱ-힣a-zA-Z0-9+#]/gi, ""),
});
setRelatedTerms(termsArray);
setId(id + 1);
setInputTerm("");
console.log(termsArray);
};
console.log(relatedTerms);
const trimmedInputTerm = inputTerm
.trim()
.replace(/[^ㄱ-힣a-zA-Z0-9+#]/gi, "");
기능적인 설명보다 타이핑에 집중해서 설명을 하겠다. onChange 함수에서 (e: React.ChangeEvent<HTMLInputElement>): void가 보일 것이다. 여지껏 그냥 귀찮아서 any 처리를 했었다. any는 우선 어떤 타입이든 다 any로 처리할 수 있는, 소위 말하는 치트키라고 한다. 근데 말이 좋아 치트키지, 사실 any로 타이핑 떡칠을 하는 것은 절대 좋지 않다. 단지 오류를 없애기 위한 타이핑에 불과하기 때문이다.
여기에서 React.ChangeEvent<HTMLInputElement>의 경우는, 글자 그대로 해석하면 된다. React에서 HTML Input 요소가 바뀌는 이벤트를 e로 지칭한 것이다. 이것을 써야하는 이유는, 그 바뀌는 값(e.target.value)을 전부 setInputTerm을 통해 inputTerm으로 지정을 해줘야 하기 때문이다. 이 e 자리에는 어떤 이벤트가 들어가는지에 따라 다르게 타이핑이 되어야 한다. 아래에 적을 onKeyUp의 파라미터 e에는 다른 타이핑이 되어있다.
void는 return값이 없을 때 사용하는 반환값인데, 여기에서는 return;(아무것도 return하지 않음을 뜻함)이 있음에도 써줬다. 사실 여기에는 그래서 void를 안 써줘도 된다. e.target.value를 그대로 setInputTerm하는 부분이라서 저 return은 어차피 중요한 부분도 아니다. 여기에 잘 나와있으므로 추가적으로 궁금한 부분이 있다면 참고하면 좋다.
termsArray는 그 relatedTerms들을 id와 text를 담아서 합치는 부분이고, trimmedInputTerm은 우리가 input에 적은 값에서 공백을 없애고 필요없는 특수문자를 전부 없애는 명령을 담은 변수이다. 이부분도 뭐 따로 타이핑이 되어있지는 않으므로 넘어가겠다.
3. onKeyUp과 onRemove, 그리고 relatedTermsList
const onKeyUp = (e: React.KeyboardEvent<HTMLDivElement>): void => {
// console.log({ trimmedInputTerm, keyCode: e.keyCode });
if (
(e.keyCode === 188 || e.keyCode === 13 || e.keyCode === 32) &&
trimmedInputTerm
) {
onClick();
}
};
const onRemove = (id: number) => {
const termsArray = relatedTerms.filter(
(relatedTerms: ITerms) => relatedTerms.id !== id
);
setRelatedTerms(termsArray);
};
const relatedTermsList = relatedTerms.map((relatedTerms: ITerms) => (
<li key={relatedTerms.id}>
{relatedTerms.text}
<button onClick={() => onRemove(relatedTerms.id)}>X</button>
</li>
));
onKeyUp을 보면 파라미터 e의 타이핑이 React.KeyoardEvent<HTMLDivElement>로 되어있다. 이역시 문자 그대로 해석하면, React에서 HTML 요소 중 div에 대해 키보드가 개입하는 이벤트를 의미한다. 여기에서는 우리가 콤마와 엔터, 스페이스를 쳤을 때 onClick 함수가 실행되도록 하였기 때문에 결국 div 요소에 키보드 이벤트를 가하는 상황이라고 볼 수 있다. 따라서 위와 같이 타이핑을 한 것이다. 그리고, return값이 없으므로 void 처리를 하였다.
onRemove 함수에 대해서는, X 키를 눌렀을 때 relatedTerms 내부에서 해당하는 id값이 아닌 다른 id값만 필터링하는 방식으로 기존에 있는 id를 없애준다. 여기에서 필요한 건 역시 id였는데, id는 숫자 타입을 갖고있다. 따라서 id의 타이핑은 숫자로 해주었다. 그리고 내부에서 relatedTerms에 대한 타이핑은 ITerms로 되어있는데, 이는 처음 선언할 때 배열 형태로 선언했던 것과는 다르게 그냥 ITerms 처리를 해주었다. 이는 이미 처음에 지정이 되어있기 때문인 것 같다. 파라미터로 갖다 쓸 때는 저렇게 쓰는 것 같은데.. 타이핑을 내가 했지만 확실하지는 않다 😂 어쨌든 여기 파라미터의 타입으로는 ITerms가 들어간다는 점..
마지막으로 relatedTermsList는 실제로 li 태그에 지금까지 만들었던 id와 text, 그리고 onRemove 함수에 대한 처리를 담당하는 실제 HTML 요소를 만드는 함수이다.
4. 마지막 return
return (
<>
<input
value={inputTerm}
onChange={onChange}
onKeyUp={onKeyUp}
// maxLength="15"
/>
<button onClick={onClick}>추가</button>
<ul id="list_terms">{relatedTermsList}</ul>
</>
);
여기는 뭐.. 딱히 설명할 건 없다. 지금까지 위에서 만들었던 것들을 하나하나 이벤트에 중괄호로 집어넣어서 실행될 수 있도록 하였다.
타입스크립트가 좀 어렵긴 한데, 타입을 하나하나 지정해가면서 이해도가 점점 느는 것 같다.
아래는 리액트 + 타입스크립트 완성본이다.
'today i learned' 카테고리의 다른 글
| today i learned 8/4 (0) | 2021.08.04 |
|---|---|
| today i learned 8/3 (0) | 2021.08.03 |
| today i learned 8/1 (0) | 2021.08.01 |
| today i learned 7/31 (0) | 2021.07.31 |
| today i learned 7/30 (0) | 2021.07.30 |