Authorization 헤더와 로그인 체크 코드를 TypeScript로 바꾸는 과정

이번 글에서는 로그인 체크 코드의 일부를 TypeScript 방식으로 어떻게 고쳐 나가는지를 단계별로 정리해보겠습니다.
특히 아래와 같은 코드 조각을 기준으로 살펴봅니다.
"Authorization" : Bearer ${token} } }); console.log(`response.ok : ${response.ok}`); if(!response.ok){ location.href="login.html"; return; } loginInfo = await response.json(); console.log(loginInfo.data); console.log('함수호출끝'); } // 토큰이 없으면 이동, 토큰이 있으면 로그인체크 if(!token){ // token === null location.href="login.html"; }else{ checkLogin(); // 페이지가 로딩되면 호출된다. getTodoList(); } </script> </body> </html>
위 코드는 일부가 잘려 있고 문법이 깨져 있지만, 의도는 분명합니다.
localStorage에서 토큰을 읽어온다.- 토큰이 없으면
login.html로 이동한다. - 토큰이 있으면
/auth/meAPI를 호출한다. - 응답이 실패하면 다시 로그인 페이지로 보낸다.
- 성공하면 로그인 사용자 정보를 사용한다.
- 그 다음 Todo 목록을 불러온다.
이 흐름을 TypeScript로 바꾸면서 더 안전하게 만들어보겠습니다.
1. 먼저 JavaScript 의도를 복원한다
문법이 깨진 부분을 복구하면 원래 의도는 대략 아래와 같습니다.
let loginInfo; const token = localStorage.getItem("token"); async function checkLogin() { console.log('함수호출시작'); const response = await fetch('https://api.fullstackfamily.com/api/edu/ws-283fc1/auth/me', { method: 'GET', headers: { "Authorization": `Bearer ${token}` } }); console.log(`response.ok : ${response.ok}`); if (!response.ok) { location.href = "login.html"; return; } loginInfo = await response.json(); console.log(loginInfo.data); console.log('함수호출끝'); } if (!token) { location.href = "login.html"; } else { checkLogin(); getTodoList(); }
이제 이 코드를 TypeScript 관점에서 고쳐보겠습니다.
2. 첫 번째 문제: token은 null일 수 있다
localStorage.getItem()의 반환값은 문자열이 아니라 string | null 입니다.
즉 아래 코드는 TypeScript에서 중요한 의미를 갖습니다.
const token = localStorage.getItem("token");
이 변수의 타입은 다음과 같습니다.
const token: string | null = localStorage.getItem("token");
왜냐하면 저장된 값이 없을 수도 있기 때문입니다.
그래서 무조건 Bearer ${token}을 만드는 것보다 먼저 token 존재 여부를 확인해야 합니다.
3. 두 번째 문제: loginInfo의 타입이 없다
JavaScript에서는 아래처럼 써도 동작합니다.
let loginInfo; loginInfo = await response.json(); console.log(loginInfo.data);
하지만 TypeScript에서는 loginInfo가 어떤 구조인지 알려주는 게 좋습니다.
예를 들어 /auth/me 응답이 아래처럼 온다고 가정해보겠습니다.
{ "data": { "id": 1, "username": "test", "nickname": "테스터" } }
그럼 인터페이스를 만들 수 있습니다.
interface UserInfo { id: number; username: string; nickname: string; } interface MeResponse { data: UserInfo; }
이제 loginInfo도 명확하게 선언할 수 있습니다.
let loginInfo: MeResponse;
4. 세 번째 문제: 비동기 함수의 반환 타입을 적어준다
기존 코드는 이렇게 되어 있습니다.
async function checkLogin() {
TypeScript에서는 반환 타입을 함께 적어주는 것이 좋습니다.
async function checkLogin(): Promise<void> {
이 함수는 값을 반환하기보다, 로그인 여부를 확인하고 필요하면 이동시키는 역할이기 때문에 Promise<void>가 잘 어울립니다.
5. Authorization 헤더를 올바르게 작성한다
문자열 보간을 사용할 때는 반드시 백틱을 써야 합니다.
잘못된 형태:
"Authorization": Bearer ${token}
올바른 형태:
"Authorization": `Bearer ${token}`
이 부분은 TypeScript 때문이라기보다 JavaScript 템플릿 문자열 문법입니다. 하지만 TypeScript로 바꾸는 과정에서 이런 문법 오류를 같이 잡아내는 효과가 있습니다.
6. 로그인 체크 후 목록 조회 순서를 정리한다
기존 코드는 아래처럼 되어 있습니다.
checkLogin(); getTodoList();
이렇게 하면 checkLogin()이 끝나기 전에 getTodoList()가 먼저 실행될 수 있습니다.
로그인 확인이 끝난 다음에 목록을 가져오고 싶다면 await를 써야 합니다.
예를 들어 초기화 함수를 따로 만들면 더 깔끔합니다.
async function init(): Promise<void> { if (!token) { location.href = "login.html"; return; } await checkLogin(); await getTodoList(); }
이렇게 하면 실행 순서가 분명해집니다.
7. TypeScript 버전으로 정리한 코드
아래는 위 내용을 반영한 예시입니다.
interface UserInfo { id: number; username: string; nickname: string; } interface MeResponse { data: UserInfo; } const token: string | null = localStorage.getItem("token"); let loginInfo: MeResponse; async function getTodoList(): Promise<void> { console.log("Todo 목록 조회"); } async function checkLogin(): Promise<void> { console.log("함수호출시작"); if (!token) { location.href = "login.html"; return; } const response: Response = await fetch( "https://api.fullstackfamily.com/api/edu/ws-283fc1/auth/me", { method: "GET", headers: { "Authorization": `Bearer ${token}` } } ); console.log(`response.ok : ${response.ok}`); if (!response.ok) { location.href = "login.html"; return; } loginInfo = await response.json() as MeResponse; console.log(loginInfo.data); console.log("함수호출끝"); } async function init(): Promise<void> { if (!token) { location.href = "login.html"; return; } await checkLogin(); await getTodoList(); } init();
8. HTML에서 TypeScript를 사용할 때 생각할 점
브라우저는 .ts 파일을 그대로 실행하지 못합니다. 그래서 실제 프로젝트에서는 보통 Vite 같은 도구를 사용해서 TypeScript를 JavaScript로 변환합니다.
예를 들면 구조를 이렇게 바꿉니다.
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Todo Web</title> </head> <body> <h1>나만의 Todo Web</h1> <script type="module" src="./src/main.ts"></script> </body> </html>
그리고 실제 로직은 main.ts 같은 파일에 넣어 관리합니다.
9. 정리
이번 변환 과정에서 중요한 포인트는 다음과 같습니다.
localStorage.getItem()의 결과는string | null이다.- API 응답은
interface로 타입을 정의해준다. async함수는Promise<void>같은 반환 타입을 적어준다.Authorization헤더는Bearer ${token}형태로 작성한다.- 로그인 확인 후 목록 조회가 실행되도록
await로 순서를 맞춘다.
TypeScript로 바꾸는 이유는 단순히 문법을 바꾸는 것이 아니라, 실수할 수 있는 지점을 코드 단계에서 미리 잡기 위해서입니다.
특히 로그인 체크처럼 흐름이 중요한 코드는 TypeScript로 정리하면 훨씬 읽기 쉽고 안전해집니다.
다음 글에서는 이어서 Todo 등록 함수 addTodo()와 목록 조회 함수 getTodoList()도 TypeScript 방식으로 바꿔보겠습니다.

댓글
댓글을 작성하려면 이 필요합니다.