TypeScript

Todo List에 타입스크립트 적용해보기

잼굴 2023. 4. 6. 17:52

기본 양식

 

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