프론트엔드 Back to the Basics : 지속 가능한 코드작성과 성능 향상법이라는 강의를 보며 읽기 쉬운 코드로 구조화하는 것에 대해 관심이 커졌습니다.
여러가지 리팩토링 방법을 보며 고칠 것들이 참 많다는 생각이 들었는데요.
그 중에서도 switch문이나 if/else if 문은 지저분한 코드를 만들기 쉽다는 것에 공감을 많이 했습니다.
const transLocationToUrl = (location: string) => {
switch (location) {
case "유성구":
return {
수거함_좌표: 유성구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.유성구,
};
case "서구":
return {
수거함_좌표: 서구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.서구,
};
case "동구":
return {
수거함_좌표: 동구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.동구,
};
case "대덕구":
return {
수거함_좌표: 대덕구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.대덕구,
};
case "중구":
return {
수거함_좌표: 중구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.중구,
};
default:
return {
수거함_좌표: 서구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.서구,
};
}
};
문자열을 해당 객체로 바꿔주는 switch문입니다.
const transLocationToUrl2 = (
location: string
): {
수거함_좌표: 수거함_정보[];
지역중앙_좌표: { x: number; y: number };
} => {
const translated = {
유성구: {
수거함_좌표: 유성구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.유성구,
},
서구: {
수거함_좌표: 서구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.서구,
},
동구: {
수거함_좌표: 동구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.동구,
},
대덕구: {
수거함_좌표: 대덕구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.대덕구,
},
중구: {
수거함_좌표: 중구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.중구,
},
};
return translated[location]; //TypeScript 오류 발생 7053
};
예전에 객체의 속성에 접근하는 방법에 대해 공부했던 적이 있습니다.
당시에는 자바스크립트로 공부했던지라 몰랐던 사실을 알게 되었는데요.
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{...}'
No index signature with a parameter of type 'string' was found on type '{...}'
타입스립트는 형식 'string'의 식을 인덱스 형식에 사용할 수 없으므로 요소에 암묵적으로 'any' 형식이 있다는 내용의 오류가 발생했습니다.
객체에서 'string' 매개 변수가 있는 인덱스 서명을 찾을 수 없습니다.
이 때 string이 아니라 string literal로 작성하여 변하지 않음을 명시적으로 알려주어야 합니다. 인덱스 서명으로 이를 해결해줄 수 있습니다.
인덱스 서명을 만들면 모든 명시적인 구성원은 인덱스 서명을 준수해야 합니다.
type translatedType = {
[index:string]:{ //인덱스 서명의 형식을 string으로
수거함_좌표: 수거함_정보[];
지역중앙_좌표: { x: number; y: number }}
}
위의 경우에는 모든 string 을 받아들이기로 서명을 하였으므로 오류가 발생하지는 않습니다.
하지만 속성 이름을 잘못 작성하더라도 오류를 발생시키지 않는다는 점이 아직 문제가 됩니다.
type 지역 = "유성구" | "서구" | "동구" | "대덕구" | "중구";
type translatedType = {
[index in 지역]:{
수거함_좌표: 수거함_정보[];
지역중앙_좌표: { x: number; y: number }}
}
이처럼 union으로 매핑한 지역이라는 타입의 이름만 사용 가능하게 제한하여 안전하게 속성을 작성할 수 있습니다.
그러면 다시 처음의 오류, 그러니까 string 형식을 인덱스 형식에 사용할 수 없다는 오류가 다시 발생하게 됩니다. 대환장
이는 인덱스 서명과는 별개로 매개변수로 들어오는 값을 타입스크립트가 확신할 수 없기 때문이라고 생각합니다.
매개변수의 타입을 string literal인 지역타입으로 확신시켜주었습니다.
최종적으로 리팩토링해본 코드는 아래와 같습니다.
type 지역 = "유성구" | "서구" | "동구" | "대덕구" | "중구";
type TranslatedType = {
[index in 지역]: {
수거함_좌표: 수거함_정보[];
지역중앙_좌표: { x: number; y: number };
};
};
const transLocationToUrl2 = (location:지역) => {
const translated:TranslatedType = {
유성구: {
수거함_좌표: 유성구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.유성구,
},
서구: {
수거함_좌표: 서구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.서구,
},
동구: {
수거함_좌표: 동구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.동구,
},
대덕구: {
수거함_좌표: 대덕구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.대덕구,
},
중구: {
수거함_좌표: 중구_수거함_좌표,
지역중앙_좌표: 지역구_지도_좌표.중구,
},
};
return translated[location];
};
오류가 가리키는 내용으로 접근하다 보니 인덱스 시그니처로 방향을 잡게 되었지만, 객체 접근을 위해서라면 매개변수의 타입을 union으로 매핑해주는 것만으로도 해결이 될 수 있을 것 같습니다. 이것이 맞다고 확신을 할 수 없어서 계속해서 고민해보려고 합니다.
인덱스 시그니처를 직접 적용하며 공부할 수 있는 기회였습니다.
남이 읽기 쉬운 코드를 작성하는 것이 한 번에 이루어지기는 쉽지 않다는 것을 느끼며 리팩토링하고 있습니다.
다른 언어를 공부해본 뒤에 배운 자바스크립트는 참 요상한 자유도를 가졌다고 생각하여 안전하게 짜기 위한 노력을 나름대로 해왔습니다.
타입스크립트를 사용하니 생각보다도 더 많은 곳에서 자유가 허용되어 왔다고 느낍니다.
작성자인 저 스스로에게도 안전한 코드를 작성할 수 있게 되는 이런 연습을 자주 하고 적용해보려고 합니다.
참고
https://radlohead.gitbook.io/typescript-deep-dive/type-system/index-signatures