Typescript로 react를 사용하는 방법을 알고난 후 지난번에 만들었던 wordle을 ts로 바꿔보았다.
Typescript를 사용하게 되면 기대했던 대로 코딩이 편해지는 지 확인하고 싶었고, error 발생도 js보다 구체적으로 일어나는지 궁금했다.
결과부터 말하자면 typescript를 이용하는 것이 기대했던 것 이상으로 좋은 방법이라는 것을 느꼈다.
변수 하나, props 하나마다 type을 지정해 주어야 한다는 것이 신경쓰이는 점이였지만, 선언 과정에서 변수에 들어갈 값을 한정하고 구현하는 것이 auto complete 등 이후의 개발 과정이나 프로그램 실행 단계에서 발생하는 오류를 의미있게 줄일 수 있었다.
기본적인 structure나 method는 이전에 구현한 js 코드와 크게 다르지 않게 구현하였다.
APP
|
-----Word
| |
| ---Letter
|
----ResultPage
Word
는 사용자가 입력하는 한 단어를 나타내는 component이며 5개의 Letter
로 이루어져 있다.
사용자는 총 7개의 Word
를 통해 정답을 찾아야 하고 게임이 종료되면 ResultPage
가 나타나게 구현하였다.
사용자가 한 단어를 입력할 때마다 각 문자의 정답 여부를 확인하게 된다.
추가적으로 기존에 구현했던 것과 달리 Letter
에 color를 입힐 때 class를 이용하지 않고 props를 이용하였다. 아무래도 React에서는 직접 DOM을 건드리는 것이 신경쓰이기도 했고 props를 이용하면 element에 class를 추가했다 지웠다 하는 작업을 할 필요가 없기 때문에 props를 통해 Letter
의 background color
를 바꿔주었다.
{colors.map((color, index) => (
<Letter
key={index}
bgcolor={
color === "G"
? "#539165"
: color === "Y"
? "#F7C04A"
: color === "B"
? "gray"
: "#dcdde1"
}
/>
))}
interface IColor {
bgcolor: string;
}
const Letter = ({ bgcolor }: IColor) => {
return <Input bgcolor={bgcolor}></Input>;
};
const Input = styled.input<IColor>`
background-color: ${(props) => props.bgcolor};
...
`
이 때 typescript에서는 interface를 통해 Letter
의 props는 bgcolor
하나만 존재하는 것과 bgcolor
의 type이 string
이라는 것을 제한할 수 있다. Letter
에 bgcolor
이외의 다른 props가 전달되거나 bgcolor
에 number
, boolean
등 string
이 아닌 값이 전달된다면 프로그램은 실행되지 않고 error를 반환할 것이다.
또한 문제의 정답인 answer
와 게임의 현재 상태를 표시해주는 isFinish
등의 state는 Recoil
을 이용하여 전역 State로 이용하였다.
Recoil
은 state 관리하는 tool이라고 알게됬는데 은근 사용 방법이 쉬워서 간단하게 사용해 보았다.
import { atom } from "recoil";
export enum STATUS {
"NOT_FINISHED",
"WIN",
"LOSE",
}
export interface IResult {
result: STATUS;
}
export const answerState = atom({
key: "answer",
default: "",
});
export const isFinishState = atom<STATUS>({
key: "isFinish",
default: STATUS.NOT_FINISHED,
});
key
는 state를 알 수 있는 고유 값이고 default
는 state의 초기값이다.
state를 component에서 사용하기 위해선 useRecoilState()
를 사용하여 기존 useState()
처럼 사용 가능하다. 혹은 state value와 modifier function을 따로따로 사용하는 것도 가능하다.
const [answer, setAnswer] = useRecoilState(answerState);
const answer = useRecoilValue(answerState);
const setAnswer = useSetRecoilState(answerState);
answer
는 string
으로 선언 하였고, 게임의 상태를 나타내주는 isFinish
는 interface 를 이용하여 "NOT_FINISHED"
, "WIN"
, "LOSE"
중에 하나의 값을 갖도록 선언하였다.
게임의 상태는 다음과 같다.
answer
를 정확하게 맞춰 다섯칸 모두 초록색이 될 때 : WIN
LOSE
NOT_FINISHED
ResultPage
는 게임이 종료되었을 때 결과 창을 나타내는 component이며 게임의 승패 여부, 정답이 무엇이였는지를 알려준다.
isFinished
가 NOT_FINISHED
일 때는 숨겨놨다가 상태가 바뀌게 되면 보여지게 하는 식으로 구현하였다.
top: ${(props) => (props.result === STATUS.NOT_FINISHED ? "-100vh" : 0)};
typescript를 사용하여 구현을 해봤는데 생각보다 코드를 편하게 짤 수 있었다. 미리 interface를 지정해 놓으면 auto complete도 잘되고 변수를 잘못 넣으면 error를 반환하니깐 시행착오를 많이 줄일 수 있었다.
새로 만드는 김에 Recoil 같은 새로운 tool도 써서 그런지 코드도 이전보다는 덜 복잡하게 정리되었다.