그렇지 않으면 typescript를 쓸 필요가 없다.
ts를 쓸 때, any
를 큰 적으로 여긴다.
그러나, 그만큼이나 적폐인건 string, Object, Function
이다.
Object
나 Function
은 string
만큼 많이 안쓰기 때문에 다루지 않겠다.
ts를 왜 쓸까?
정적분석을 위해서
이다.
타입스크립트 공식문서
TypeScript is JavaScript’s runtime with a compile-time type checker
공식문서에서도 말하듯이 typescript는 그냥 javascript
의 정적 타입 검사자이다.
정적분석을 한다는건 엄청나게 대단한 요소이다.
코드를 실행하기 전에 정적인 환경에서 미리 에러를 발견할 수 있음과 동시에
정적 분석을 하기 때문에 극적인 intellisense
를 활용할 수 있다.
오늘 알아볼건, type을 string으로 했을때 어떤 문제들이 발생할 수 있는지 알아보자
ex) 지도를 관리할때 info를 담은 state를 관리하는 훅을 하나 만들었다고 생각하자
info의 state에는 zoom, center, mapState, cursor를 담을 것이다.
interface MapInfoState {
zoom: number;
center: [number,number];
mapState: string;
cursor: Object;
}
export const useMapInfo = () => {
const state:MapInfoState = {
zoom: 5,
mapState: "idle",
center: [0, 0],
cursor: { style: "none", text: "" },
};
const setState = <Key extends keyof MapInfoState>(key: Key, value: MapInfoState[Key]) => {
state[key] = value;
};
return {
state,
setState,
};
}
이런식으로 코드를 짰다면? 어떤부분에서 문제가 발생할까?
setState를 한다고 생각해보자
const mapInfo = useMapInfo()
mapInfo.setState('mapState','???')
mapInfo.setState('cursor',{})
여기서 아무런 문제가 발생하지 않는다. 즉 이 코드를 사용하는 입장에서 useCase를 확인하던가, 아니면 소스를 추적하면서, 어떤값이 들어갈 수 있는지 확인해야한다.
그렇다면 어떻게 개선할 수 있을까?
현재의 Map의 상태를 나타내는 MapState같은 경우의 타입은 미리 지정할 수 있다.
그리고 그렇게 사용을 하기를 권장할 것이다.
예를들어 미리 타입을 "idle" | "loading" | "success" | "error"
만 가능하다고 지정해 놓는다면,
Cusrosr의 State가 될 수 있는게 { style: "none"; text: "" } | { style: "pointer"; text: string }
라고 미리 지정을 해놓는다면 어떤 이점이 생길까?
type MapState = "idle" | "loading" | "success" | 'error';
type CursorState = { style: "none"; text: "" } | { style: "pointer"; text: string };
interface MapInfoState {
zoom: number;
center: [number,number];
mapState: MapState;
cursor: CursorState;
}
export const useMapInfo = () => {
const state:MapInfoState = {
zoom: 5,
mapState: "idle",
center: [0, 0],
cursor: { style: "none", text: "" },
};
const setState = <Key extends keyof MapInfoState>(key: Key, value: MapInfoState[Key]) => {
state[key] = value;
};
return {
state,
setState,
};
}
의 형식으로 코드를 작성하고
const mapInfo = useMapInfo()
mapInfo.setState('mapState','???')
mapInfo.setState('cursor',{})
바로 오류가 발생한다.
Argument of type '"???"' is not assignable to parameter of type 'MapState'.(2345)
Argument of type '{}' is not assignable to parameter of type 'CursorState'.(2345)
이러한 union type을 통한 type safe를 가능하게 할 수 있다.
vscode 기준으로
const mapInfo = useMapInfo()
mapInfo.setState('mapState','여기')
여기
에 들어갈 부분을 스페이스바로만 찾아가면서 코드를 작성하는건 꽤나 짜릿한 경험이다.
물론 이건 코드를 작성하는 과정에서의 문제이고, 로직을 실행하는 부분에서는 이렇게 하지 않고 좀 더 안전하게 ts-pattern같은 라이브러리를 활용하면 더 좋은 결과를 만들 수 있을 것 같다.