반응형
1. tsconfig.json에 대하여
타입스크립트를 자바스크립트로 변환(컴파일-프로그래밍 언어를 다른 언어로 변경함)할 때 여러 가지 옵션을 줘서 다양한 방식으로 변경할 수가 있다.
자바스크립트를 공부한 사람이라면 알고 있듯이, 자바스크립트는 표준 자체만으로도 버전이 엄청나게 많다. 그래서 타입스크립트 변환 옵션 중에 대표적인 것이 어떤 버전의 자바스크립트로 타깃 하느냐도 있다.
이 옵션은 대부분의 node 프로젝트와 같이 json파일 규격으로 지정해두는데, 타입스크립트를 위한 옵션 파일은
파일명을 "tsconfig.json"으로 지정해야한다.
먼저 tsconfig.json을 생성해보자.
tsconfig.json
{
"compilerOptions": {
"strict": true,
"target": "ES5",
"module": "CommonJS",
"alwaysStrict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"sourceMap": true,
"downlevelIteration": true
}
}
2. 타입스크립트 프로젝트 형태로 코드 변경
그리고 이전의 app.js를 app.ts로 확장자를 변경한다.
(.ts는 타입스크립트 확장자이다.)
app.ts
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();
그리고 이 파일을 호출하는 HTML 파일에서도 script 부분의 파일명을 app.ts로 변경한다.
<!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.ts" type="module"></script>
</body>
</html>
3. 참고할만한 글
1) tsconfig.json이란 무엇인가?
https://www.typescriptlang.org/ko/docs/handbook/tsconfig-json.html
2) tsconfig reference 페이지
https://www.typescriptlang.org/tsconfig
반응형