-
타입스크립트 왜 쓰나요?Ts 2024. 11. 11. 21:40
이 글은 JS만 쓰던 내가 처음으로 Ts를 강제로 배우면서 느꼈던 고통이, 사용했을 때의 편리함을 미리 알았다면 고통스럽지는 않았을 것 같았다 라는 마음으로 글을 작성한다.
뭐..였더라?
런타임 에러, 리팩토링, 협업, 휴먼에러 등등 거창한 말과 이론을 뒤로하고, 왜써야하는지 딱 한마디로 정리하자면
‘뭐..였더라?’ 일 것 같다.
코드를 작성하다보면 많은 변수와, 많은 함수들 그리고 서버에서 받아오는 많은 데이터들을 다룰 때, 누가 누구였는지 이 함수에 어떤 파라미터를 넘겨야하는지 완벽하게 모두 기억할 수는 없을 것이다. 그때 내 스스로 내 변수에 명찰을 붙여 누군지 파악하는게 타입스크립트의 가장 큰 출발점이라고 나는 생각한다.
나의 경험
"아차차 s빼먹었네.."
npm run dev 탁탁 → "어?"
"어 이 api응답 값 뭐였더라"
나는 이런 경험이 잦았다. 특히 공통컴포넌트를 만들 때 자식컴포넌트로 내려야 할 값들을 빼먹었다던가, 오타가 났던 경험이있다.
1. 극단적으로 공통컴포넌트 input을 만든다고 가정해보자.
LoginFormInput의 type에 ‘text’ , ‘email’ , ‘number’ , ‘password’ 여러가지들이 존재하고, 타입에 알맞는 디자인이 구현되었다. 해당 input을 다른 컴포넌트에서 import하고 다음과 같이 작성하였다.
LoginFormInput({ label='password' type = 'pasword' name='loginFormPssword' placehoder='비밀번호를 입력해주세요' })
한눈에 들어오기 상당히 힘들다. 심지어 개발을 하다보면 주석 또는 실제 한국어 텍스트를 태그에 담을 일도 빈번히 있다보니 한글과 영어을 번갈아 사용하다보면 오타도 나기 쉽상이다.
이럴 때 type으로 와야하는 이름표를 명확하게 구분이 된다면 한자 한자 직접작성할 필요도 없고, 이 컴포넌트에 어떠한 값을 내려줘야하는지 한눈에 파악가능하다.
(심지어 필수적으로 전달해야할 prop들이 아직 다 작성되지 않았기에 FormInput에 밑줄로 에러표시를 도와준다.)
2. 변수 타입 확인하기
const {data} = await basicApi.get(`activities/${activityId}`);
다음과 같이 api응답으로 어떠한 data를 받는다고 생각하자. 이 코드는 내가 작성한 오래전의 코드가 될 수 있고, 협업하는 팀원이 작성한 코드가 될 수 도 있다. 만약 타입스크립트를 사용하지 않았더라면, 이 api가 어떤 값을 반환하는지, 이 걸로 어떠한 코드를 작성하였는지 유추하기가 힘들 것이다.
const { data } = await basicApi.get<Activity>(`activities/${activityId}`);
위 코드에서 딱 하나 <Activity> 만 추가되었지만 이 api가 무엇을 반환하는지 파악하는 것은 이제 1초면 된다. data에 마우스를 얹으면 끝난다. 이제 이게 뭐..였더라.. 가 해결되는 것이다.
export interface Activity { id: number; userId: number; title: string; description: string; category: string; price: number; address: string; bannerImageUrl: string; rating: number; reviewCount: number; createdAt: string; updatedAt: string; }
‘아 data에는 작성된 어떠한 상품에 대한 모든 정보가 들어있구나’ → ‘아 상품 상세보기 페이지에서 쓰이는 건가?’ 정도로만 생각해도 저 아래의 모든 코드들이 읽기 수월하게 될 것이다.
3. 그 외)
약간의 이론
최소한으로 알고쓰면 좋을 만한 이론이다.
자바스크립트
자바스크립트는 웹 브라우저에서 실행되는 프로그래밍 언어로서, 웹페이지를 ‘동적’ 으로 만들어주는 동적 타입이다.
동적? 타입?
여기서의 타입은 쉽게말해서 종류, 음식의 종류정도면 될 것같다. 양식 중식 일식 한식처럼 int형 , short형, float형, bool형, 객체 등으로 나뉘어진 변수의 종류다.
이 동적타입의 특징은
let variable = "문자열"; // 문자열 타입 variable = 123; // 숫자 타입으로 변경 가능 variable = true; // 불리언 타입으로 변경 가능
자유롭게 타입선언 없이 변수를 사용하고 변경이 가능하고, 실행 시점에 타입을 검사한다.
빠른 개발 속도로 유연하고도 쉽게 학습이 가능하다고 볼 수 있다. 단점으로는 실행전까지 오류를 발견할 수 없고, 의도치 않는 타입변환이 될 수 있다는 점이 존재한다.
function add(x, y) { return x + y; } add(5, 3); // 실행후 결과 : 8 add("5", 3); // 실행후 결과 : "53" (의도치 않은 문자열 연결)
여기서의 실행은 런타임을 의미하는데,
개발자는 코드를 작성하고 컴파일이라는 과정을 통해 기계어 코드로 변환시켜 실행 가능한 프로그램이 되고, 이 과정을 마친 프로그램을 실행시키면 이때의 프로그램이 동작되는 시간을 런타임 이라고 칭한다.
자바스크립트는 인터프리터 언어로, 코드가 한줄 한줄 직접 실행되며 별도의 컴파일 과정이 없고, 실행 시점 즉 런타임을 가지고 나서야 오류가 발견된다.
반대로
타입스크립트
타입스크립트는 정적 타입이다. 이 정적타입은 작성자가 코드의 변수 타입을 직접 작성하는 언어이다. 만약 컴파일 시 해당 변수의 타입에 알맞지 않는 값이 들어가있다면 컴파일 에러가 발생하게 된다. 이렇게 하나하나 직접 적으니, 의도치않는 타입관련 에러를 초기에 발견할 수 도 있다 . 또한 글 윗부분에 적어두었던 변수에 값을 한번에 확인 가능하니, 협업이나 프로젝트할 때 유지보수가 동적타입의 언어보다 유리하다.
// 변수에 타입을 명시 let name: string = "홍길동"; let age: number = 25; let isStudent: boolean = true; // 객체의 형태도 정의 가능 interface Person { name: string; age: number; } const person: Person = { name: "홍길동", age: 25 // 다른 속성을 추가하면 에러 발생 };
그리고 Ts는 컴파일 언어로서, 자바스크립트로 변환(컴파일)되며 실행 전에 오류를 발견할 수 있다.
컴파일 예시)
function greet(name: string) { return `안녕하세요, ${name}님!`; } let userName: string = "홍길동"; console.log(greet(userName)); // 이코드를 컴파일 하면 아래와 같다. function greet(name) { return "안녕하세요, " + name + "님!"; } var userName = "홍길동"; console.log(greet(userName));
그리고 단계별 컴파일 과정은
- TS 코드 → 타입 검사
- 타입검사 → 컴파일
- 컴파일 → JS 코드
- JS코드 → 브라우저 실행
다음과 같다.
사용에 대하여 거창한 것은 없다.
Ts를 사용하면 실시간으로 타입 체킹도 가능하고, 타입오류가 난 부분들에 밑줄이 알아서 쳐질 것이다. 이러한 기능은 Ts의 컴파일러가 실시간으로 코드를 분석하면서 제공하기 때문에 실제로 Js로 변환(컴파일) 이전에, 코드 작성 단계에서 많은 문제를 미리 발견하고 수정할 수 있게 도움을 줄 것이다.
그래서 어떻게 쓰라고
그건 아직도 명확하게 모르겠다. 다만 자주 쓰는 패턴들이 정해져있고, 이 것이 아직 실력에 비례하다고 생각하기 때문에, 추후 더많은 것들을 사용할 꺼라고 생각이 든다.
1. api의 req body에 대한 타입 정의
2. 자주 사용하는 util함수나 hook의 파라미터 타입 정의
3. 자식 컴포넌트의 파라미터 타입 정의
4. 자주 사용되는 객체의 타입 정의
5. 공통컴포넌트에서 사용될 타입 정의 등등 이 될 수도 있겠다.
어쨌든 ‘이거 자주쓰이네’ ‘이거 많이쓰이네’ 하는 것들을 하나 둘 정리해가면 Ts에 대한 이해도가 많이 올라갈 것 이라고 생각한다. 처음부터 너무 많이 다 정리하려고 하면 Ts는 꼴도 보기 싫어지는 것 같았다.
물론 지금도 그렇다.