Skip to content

Instantly share code, notes, and snippets.

@thesephist
Created May 26, 2018 09:08
Show Gist options
  • Save thesephist/e3b35bea6a3318407ee28a92dc43d858 to your computer and use it in GitHub Desktop.
Save thesephist/e3b35bea6a3318407ee28a92dc43d858 to your computer and use it in GitHub Desktop.
TypeScript Todo Example (incl. baseline webpack + tsconfig)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>TypeScript Practice</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: sans-serif;
max-width: 800px;
margin: 20px auto;
}
</style>
</head>
<body>
<main></main>
<script src="/js/main.min.js"></script>
</body>
<
let __taskid_ref = 0;
const taskid = (): number => {
return __taskid_ref ++;
}
interface Component {
html(): string;
}
interface ClickEvent extends Event {
readonly target: HTMLElement;
}
interface KeyboardEvent extends Event {
readonly target: HTMLElement;
}
class TaskComponent implements Component {
readonly id: number = taskid();
private name: string;
constructor({
name = 'Do something...',
} = {}) {
this.name = name;
}
html(): string {
return `<li class="task" data-id="${this.id}">
${this.name}
<button class="removeButton">X</button>
</li>`;
}
setName(name: string): void {
this.name = name;
}
}
class ListComponent implements Component {
tasks: TaskComponent[];
constructor({
tasks = [],
}: {
tasks?: TaskComponent[],
} = {}) {
this.tasks = [];
}
addTask(value: string): void {
this.tasks.push(new TaskComponent({name: value}));
}
removeTask(id: number) {
this.tasks = this.tasks.filter(t => t.id !== id);
}
html(): string {
return `<ul class="list">
${this.tasks.map(t => t.html()).join(' ')}
</ul>`;
}
}
class TodoApp implements Component {
readonly list: ListComponent = new ListComponent();
addTask(value: string): void {
this.list.addTask(value);
render();
}
removeTask(id: number): void {
this.list.removeTask(id);
render();
}
html(): string {
return `
<h1>To-do List</h1>
<input type="text" id="todoInput">
<button id="addButton">Add</button>
<div class="todolist">
${this.list.html()}
</div>
`;
}
}
// Main calls
const $main: HTMLElement = document.querySelector('main');
let $input: HTMLInputElement;
let $addButton: HTMLButtonElement;
const app = new TodoApp();
const render = (): void => {
$main.innerHTML = app.html();
$input = document.querySelector('#todoInput');
$addButton = document.querySelector('#addButton');
}
render();
// Other App Elements. It's kinda dirty b/c my component model is fucked up.
// Add listeners
$main.addEventListener('click', (evt: ClickEvent): void => {
if (evt.target.classList.contains('removeButton')) {
const taskid: number = +evt.target.parentElement.getAttribute('data-id');
app.removeTask(taskid);
} else if (evt.target.id === 'addButton') {
if ($input.value.trim()) {
app.addTask($input.value.trim());
$input.value = '';
$input.focus();
}
}
});
$main.addEventListener('keypress', (evt: KeyboardEvent): void => {
if (evt.target.id == 'todoInput') {
if (evt.keyCode === 13 && $input.value.trim()) {
app.addTask($input.value.trim());
$input.value = '';
$input.focus();
}
}
});
{
"name": "ts-practice",
"version": "1.0.0",
"description": "Intro to TypeScript",
"main": "index.js",
"author": "Linus Lee",
"license": "MIT",
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack-cli": "^2.1.4",
"webpack": "^4.9.1",
"ts-loader": "^4.3.0",
"typescript": "^2.8.3"
}
}
{
"compilerOptions": {
"outDir": "./static/js/",
"sourceMap": true,
"noImplicitAny": true,
"module": "ESNext",
"target": "ESNext",
}
}
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/main.ts',
devtool: 'inline-source-map',
watch : true,
watchOptions: {
ignored: /node_modules/,
},
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: '/node_modules/'
}
]
},
resolve: {
extensions: ['.ts', '.js']
},
output: {
filename: 'main.min.js',
path: path.resolve(__dirname, 'static/js')
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment