반응형
1. 타입스크립트란?
타입스크립트(Typescript)는 타입이 유연한 자바스크립트에 좀 더 엄격하게 타입을 줄 수 있는 언어이다. 타입을 명시할 수 있는 버전의 자바스크립트라고 생각하면 되고, 여러 실수를 잡기 위해서 타입스크립트로 코딩한 다음에 자바스크립트로 변환해서 사용한다.
2. 변환할 코드
타입스크립트 공부를 위해서 Hackers News API를 통해 간단하게 구현한 예제를 사용할 것이다.
아래 예제를 타입스크립트로 부분적으로 바꿔볼 것이고, 바꾸면서 장점에 대해서도 함께 기술할 예정이다.
본 수업은 패스트캠퍼스의 "김민태의 프론트엔드 아카데미 : 제 1강 JS & TS Essential"의 내용을 따왔다.
예제 코드:
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>HN client</title>
<link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" />
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root">
</div>
<script src="./app.js" type="module"></script>
</body>
</html>
app.js
const container = document.getElementById('root');
const ajax = new XMLHttpRequest();
const NEWS_URL = 'https://api.hnpwa.com/v0/news/1.json';
const CONTENT_URL = 'https://api.hnpwa.com/v0/item/@id.json';
const store = {
currentPage: 1,
feeds: [],
};
function getData(url) {
ajax.open('GET', url, false);
ajax.send();
return JSON.parse(ajax.response);
}
function makeFeeds(feeds) {
for (let i = 0; i < feeds.length; i++) {
feeds[i].read = false;
}
return feeds;
}
function newsFeed() {
let newsFeed = store.feeds;
const newsList = [];
let template = `
<div class="bg-gray-600 min-h-screen">
<div class="bg-white text-xl">
<div class="mx-auto px-4">
<div class="flex justify-between items-center py-6">
<div class="flex justify-start">
<h1 class="font-extrabold">Hacker News</h1>
</div>
<div class="items-center justify-end">
<a href="#/page/{{__prev_page__}}" class="text-gray-500">
Previous
</a>
<a href="#/page/{{__next_page__}}" class="text-gray-500 ml-4">
Next
</a>
</div>
</div>
</div>
</div>
<div class="p-4 text-2xl text-gray-700">
{{__news_feed__}}
</div>
</div>
`;
if (newsFeed.length === 0) {
newsFeed = store.feeds = makeFeeds(getData(NEWS_URL));
}
for(let i = (store.currentPage - 1) * 10; i < store.currentPage * 10; i++) {
newsList.push(`
<div class="p-6 ${newsFeed[i].read ? 'bg-red-500' : 'bg-white'} mt-6 rounded-lg shadow-md transition-colors duration-500 hover:bg-green-100">
<div class="flex">
<div class="flex-auto">
<a href="#/show/${newsFeed[i].id}">${newsFeed[i].title}</a>
</div>
<div class="text-center text-sm">
<div class="w-10 text-white bg-green-300 rounded-lg px-0 py-2">${newsFeed[i].comments_count}</div>
</div>
</div>
<div class="flex mt-3">
<div class="grid grid-cols-3 text-sm text-gray-500">
<div><i class="fas fa-user mr-1"></i>${newsFeed[i].user}</div>
<div><i class="fas fa-heart mr-1"></i>${newsFeed[i].points}</div>
<div><i class="far fa-clock mr-1"></i>${newsFeed[i].time_ago}</div>
</div>
</div>
</div>
`);
}
template = template.replace('{{__news_feed__}}', newsList.join(''));
template = template.replace('{{__prev_page__}}', store.currentPage > 1 ? store.currentPage - 1 : 1);
template = template.replace('{{__next_page__}}', store.currentPage + 1);
container.innerHTML = template;
}
function newsDetail() {
const id = location.hash.substr(7);
const newsContent = getData(CONTENT_URL.replace('@id', id))
let template = `
<div class="bg-gray-600 min-h-screen pb-8">
<div class="bg-white text-xl">
<div class="mx-auto px-4">
<div class="flex justify-between items-center py-6">
<div class="flex justify-start">
<h1 class="font-extrabold">Hacker News</h1>
</div>
<div class="items-center justify-end">
<a href="#/page/${store.currentPage}" class="text-gray-500">
<i class="fa fa-times"></i>
</a>
</div>
</div>
</div>
</div>
<div class="h-full border rounded-xl bg-white m-6 p-4 ">
<h2>${newsContent.title}</h2>
<div class="text-gray-400 h-20">
${newsContent.content}
</div>
{{__comments__}}
</div>
</div>
`;
for(let i=0; i < store.feeds.length; i++) {
if (store.feeds[i].id === Number(id)) {
store.feeds[i].read = true;
break;
}
}
function makeComment(comments, called = 0) {
const commentString = [];
for(let i = 0; i < comments.length; i++) {
commentString.push(`
<div style="padding-left: ${called * 40}px;" class="mt-4">
<div class="text-gray-400">
<i class="fa fa-sort-up mr-2"></i>
<strong>${comments[i].user}</strong> ${comments[i].time_ago}
</div>
<p class="text-gray-700">${comments[i].content}</p>
</div>
`);
if (comments[i].comments.length > 0) {
commentString.push(makeComment(comments[i].comments, called + 1));
}
}
return commentString.join('');
}
container.innerHTML = template.replace('{{__comments__}}', makeComment(newsContent.comments));
}
function router() {
const routePath = location.hash;
if (routePath === '') {
newsFeed();
} else if (routePath.indexOf('#/page/') >= 0) {
store.currentPage = Number(routePath.substr(7));
newsFeed();
} else {
newsDetail()
}
}
window.addEventListener('hashchange', router);
router();
본 코드에 대한 설명은 "Javascript" 카테고리에 향후 게시할 예정이다.
예시코드를 실행하기 위해서는 "웹 번들링"을 진행해야한다.
이 코드는 parcel.js를 통해서 번들링을 진행했다.
기본적으로 parcel.js를 사용하는 방법을 알아야 한다.
3. 참고할만한 글
1) 타입스크립트 핸드북 (공식)
https://www.typescriptlang.org/docs/handbook/intro.html
2) Parcel.js 사용하기
https://ko.parceljs.org/getting_started.html
끝!
반응형