HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Todo List</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<h1>Todo List</h1>
<form>
<input type="text" id="inputTodo" placeholder="Add Todo">
<button type="submit">Add</button>
</form>
<ul id="todoList"></ul>
<button id="clearButton">Clear All</button>
<script src="index.js"></script>
</body>
</html>
CSS
* {
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
h1 {
text-align: center;
}
form {
display: flex;
justify-content: center;
margin-top: 20px;
}
input[type="text"] {
padding: 10px;
border-radius: 5px;
border: 1px solid #ccc;
margin-right: 10px;
width: 70%;
}
button[type="submit"] {
padding: 10px;
border-radius: 5px;
border: none;
background-color: #4CAF50;
color: white;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
margin: 10px 0;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
display: flex;
justify-content: space-between;
}
li span {
margin-right: 10px;
}
#clearButton {
margin-top: 20px;
padding: 10px;
border-radius: 5px;
border: none;
background-color: #f44336;
color: white;
}
JavaScript
const form = document.querySelector('form');
const inputTodo = document.querySelector('#inputTodo');
const todoList = document.querySelector('#todoList');
const clearButton = document.querySelector('#clearButton');
let todos = [];
function renderTodos() {
todoList.innerHTML = '';
todos.forEach((todo) => {
const li = document.createElement('li');
li.innerHTML = `${todo.text} <span class="delete" data-index="${todo.index}">삭제</span>`;
todoList.appendChild(li);
});
}
form.addEventListener('submit', (e) => {
e.preventDefault();
if (!inputTodo.value)
return;
const newTodo = {
text: inputTodo.value,
index: todos.length,
};
todos.push(newTodo);
inputTodo.value = '';
renderTodos();
localStorage.setItem('todos', JSON.stringify(todos));
});
todoList.addEventListener('click', (e) => {
const target = e.target;
if (!target.classList.contains('delete'))
return;
const index = parseInt(target.dataset.index);
todos = todos.filter((todo) => todo.index !== index);
renderTodos();
localStorage.setItem('todos', JSON.stringify(todos));
});
clearButton.addEventListener('click', () => {
if (confirm('정말 모두 삭제하시겠습니까?')) {
todos = [];
renderTodos();
localStorage.removeItem('todos');
}
});
일단 기본 기능만 가지고 Todo 앱을 뚝딱 만들었따.
이제 타입스크립트로 적용해보자
TypeScript
const form: HTMLFormElement | null = document.querySelector('form');
const inputTodo: HTMLInputElement | null = document.querySelector('#inputTodo');
const todoList: HTMLUListElement | null = document.querySelector('#todoList');
const clearButton: HTMLButtonElement | null = document.querySelector('#clearButton');
interface Todo {
text: string;
index: number;
}
let todos: Todo[] = [];
function renderTodos(): void {
todoList.innerHTML = '';
todos.forEach((todo: Todo): void => {
const li: HTMLLIElement = document.createElement('li');
li.innerHTML = `${todo.text} <span class="delete" data-index="${todo.index}">삭제</span>`;
todoList.appendChild(li);
});
}
form.addEventListener('submit', (e: Event): void => {
e.preventDefault();
if (!inputTodo.value) return;
const newTodo: Todo = {
text: inputTodo.value,
index: todos.length,
};
todos.push(newTodo);
inputTodo.value = '';
renderTodos();
localStorage.setItem('todos', JSON.stringify(todos));
});
todoList.addEventListener('click', (e: MouseEvent): void => {
const target = e.target as HTMLElement;
if (!target.classList.contains('delete')) return;
const index: number = parseInt(target.dataset.index!);
todos = todos.filter((todo: Todo): boolean => todo.index !== index);
renderTodos();
localStorage.setItem('todos', JSON.stringify(todos));
});
clearButton.addEventListener('click', (): void => {
if (confirm('정말 모두 삭제하시겠습니까?')) {
todos = [];
renderTodos();
localStorage.removeItem('todos');
}
});
전체 코드이다.
1. 상수에 타입을 정해준다. HTML타입을 정해주고 혹시몰라서 null도 해줬따
const form: HTMLFormElement | null = document.querySelector('form');
const inputTodo: HTMLInputElement | null = document.querySelector('#inputTodo');
const todoList: HTMLUListElement | null = document.querySelector('#todoList');
const clearButton: HTMLButtonElement | null = document.querySelector('#clearButton');
2. 계속 사용하게 될 Todo의 타입을 정해줬다. 내용은 text이고 index는 숫자이니까 string과 number로 해줬다.
interface Todo {
text: string;
index: number;
}
let todos: Todo[] = [];
3. 함수들은 작동은 하지만 return값이 없기 때문에 void를 줬고, 이벤트 핸들러에 Event 타입을 줬다.
function renderTodos(): void {
// ...
}
form.addEventListener('submit', (e: Event): void => {
// ...
});
todoList.addEventListener('click', (e: MouseEvent): void => {
// ...
});
4. 기존 JS에는 없던것이다. 기존에는 'inputTodo'에서 얻은 값을 직접 'todos' 배열에 추가했지만, 타입스크립트에서는 새로운 변수를 선언해서 할당 해주는게 좋다.
1. 가독성
2. 디버깅 쉬워짐
3. 코드 유지보수 쉬워짐
const newTodo: Todo = {
text: inputTodo.value,
index: todos.length,
};
5. as로 e.target의 속성을 HTMLElement로 지정해준다.
const target = e.target as HTMLElement;
6. parseInt()로 index값을 숫자로 바꿔줬다.
const index: number = parseInt(target.dataset.index!);
'TypeScript' 카테고리의 다른 글
타입스크립트 머리박기 2일차 복기 (0) | 2023.01.16 |
---|---|
타입스크립트 머리박기 1일차 복기 (0) | 2023.01.13 |