1.tsconfig.json
{
"compilerOptions": {
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"outDir": "./public", /* Redirect output structure to the directory. */
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"strict": true, /* Enable all strict type-checking options. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"include": ["src"]
}
2.src/app.js
import { Invoice } from './classes/Invoice.js';
import { Payment } from './classes/Payment.js';
import { ListTemplate } from './classes/ListTemplate.js';
import { HasFormatter } from './interfaces/HasFormatter.js';
// let docOne: HasFormatter;
// let docTwo: HasFormatter;
// docOne = new Invoice('yoshi', 'web work', 250);
// docTwo = new Payment('mario', 'plumbing', 200);
// let docs: HasFormatter[] = [];
// docs.push(docOne);
// docs.push(docTwo);
const form = document.querySelector('.new-item-form') as HTMLFormElement;
console.log(form.children);
// inputs
const type = document.querySelector('#type') as HTMLInputElement;
const tofrom = document.querySelector('#tofrom') as HTMLInputElement;
const details = document.querySelector('#details') as HTMLInputElement;
const amount = document.querySelector('#amount') as HTMLInputElement;
// list template instance
const ul = document.querySelector('ul')!;
const list = new ListTemplate(ul);
form.addEventListener('submit', (e: Event) => {
e.preventDefault();
let doc: HasFormatter;
if (type.value === 'invoice') {
doc = new Invoice(tofrom.value, details.value, amount.valueAsNumber);
} else {
doc = new Payment(tofrom.value, details.value, amount.valueAsNumber);
}
list.render(doc, type.value, 'end');
});
3. src/interfaces/HasFormatter.ts
export interface HasFormatter {
format(): string;
}
4. src/classes/Invoice.ts
import { HasFormatter } from '../interfaces/HasFormatter.js';
export class Invoice implements HasFormatter {
constructor(
readonly client: string,
private details: string,
public amount: number,
){}
format() {
return `${this.client} owes £${this.amount} for ${this.details}`;
}
}
5. src/classes/Payment.ts
import { HasFormatter } from '../interfaces/HasFormatter.js';
export class Payment implements HasFormatter{
constructor(
readonly recipient: string,
private details: string,
public amount: number,
){};
format() {
return`${this.recipient} is owed £${this.amount} for ${this.details}`;
}
}
5. public/index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TypeScript Tutorial</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="wrapper">
<h1>Finance Logger</h1>
<!-- output list -->
<ul class="item-list">
</ul>
</div>
<footer>
<form class="new-item-form">
<div class="field">
<label>Type:</label>
<select id="type">
<option value="invoice">Invoice</option>
<option value="payment">Payment</option>
</select>
</div>
<div class="field">
<label>To / From:</label>
<input type="text" id="tofrom">
</div>
<div class="field">
<label>Details:</label>
<input type="text" id="details">
</div>
<div class="field">
<label>Amount (£):</label>
<input type="number" id="amount">
</div>
<button>Add</button>
</form>
<a href="https://www.thenetninja.co.uk">The Net Ninja</a>
</footer>
<script type="module" src='app.js'></script>
</body>
</html>
6.src/classes/ListTemplate.ts
import { HasFormatter } from "../interfaces/HasFormatter";
export class ListTemplate {
constructor(private container: HTMLUListElement){}
render(item: HasFormatter, heading: string, pos: 'start' | 'end'){
const li = document.createElement('li');
const h4 = document.createElement('h4');
h4.innerText = heading;
li.append(h4);
const p = document.createElement('p');
p.innerText = item.format();
li.append(p);
if(pos === 'start'){
this.container.prepend(li);
} else {
this.container.append(li);
}
}
}