Knockout.jsとTypeScriptでシンプルTodoアプリを作ってみよう
TypeScript を用いた Knockout.js プログラミング
Knockout.js は、JavaScript フレームワークであり、DOM 操作とデータバインディングを容易にすることで、Web アプリケーション開発を簡素化します。TypeScript は、JavaScript の静的型付けスーパーセットであり、型安全性を向上させ、開発者の生産性を高めることができます。
TypeScript を使用して Knockout.js アプリケーションを開発すると、次のような利点があります。
- 保守性の向上: 型情報により、コードをより理解しやすく、保守しやすくなります。
- 開発者の生産性向上: 型推論とコード補完により、開発者はコードをより速く簡単に記述できます。
- 型安全性: TypeScript の型システムにより、実行時エラーを防ぎ、コードの信頼性を高めることができます。
TypeScript で Knockout.js を使用する基本的な手順
- TypeScript プロジェクトを設定する: TypeScript コンパイラ (tsc) と、型定義ファイル (.d.ts) を含むプロジェクトを設定する必要があります。
- Knockout.js コンポーネントを TypeScript クラスとして定義する: Knockout.js コンポーネントを TypeScript クラスとして定義し、コンポーネントのプロパティとメソッドに型を指定する必要があります。
- データバインディングを使用する: Knockout.js のデータバインディング機能を使用して、コンポーネントのプロパティを DOM 要素にバインドします。
以下の例は、TypeScript で単純なカウンターアプリケーションを作成する方法を示しています。
// Knockout.js コンポーネントを定義する TypeScript クラス
class CounterComponent {
// コンポーネントのプロパティに型を指定
count: number = 0;
// コンポーネントのメソッドに型を指定
increment(): void {
this.count++;
}
}
// Knockout.js を使用してコンポーネントをバインド
ko.applyBindings(new CounterComponent());
この例では、CounterComponent
という名前の TypeScript クラスを定義しています。このクラスには、count
という名前のプロパティと、increment
という名前のメソッドがあります。count
プロパティには、number
型が指定されています。これは、count
プロパティが数値のみを格納できることを意味します。increment
メソッドには、void
型が指定されています。これは、increment
メソッドが値を返さないことを意味します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todo アプリケーション</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-min.js"></script>
<script src="app.ts"></script>
</head>
<body>
<h1>Todo アプリケーション</h1>
<ul data-bind="foreach: todos">
<li>
<input type="checkbox" data-bind="checked: completed" />
<span data-bind="text: name"></span>
<button data-bind="click: $parent.removeTodo">削除</button>
</li>
</ul>
<input type="text" data-bind="value: newTodo, enter: addTodo" placeholder="新しい Todo を入力...">
<script>
// Knockout.js コンポーネントを定義する TypeScript クラス
class Todo {
name: string;
completed: boolean;
constructor(name: string) {
this.name = name;
this.completed = false;
}
}
// Knockout.js ViewModel を定義する TypeScript クラス
class TodoViewModel {
todos: KnockoutObservableArray<Todo>;
newTodo: KnockoutObservable<string>;
constructor() {
this.todos = ko.observableArray([]);
this.newTodo = ko.observable("");
}
addTodo(): void {
const newTodo = this.newTodo();
if (newTodo) {
this.todos.push(new Todo(newTodo));
this.newTodo("");
}
}
removeTodo(todo: Todo): void {
this.todos.remove(todo);
}
}
// Knockout.js ViewModel をインスタンス化し、DOM にバインド
const viewModel = new TodoViewModel();
ko.applyBindings(viewModel);
</script>
</body>
</html>
TypeScript コード (app.ts)
// TypeScript コンパイラ (tsc) でコンパイルする必要があります
class Todo {
name: string;
completed: boolean;
constructor(name: string) {
this.name = name;
this.completed = false;
}
}
class TodoViewModel {
todos: KnockoutObservableArray<Todo>;
newTodo: KnockoutObservable<string>;
constructor() {
this.todos = ko.observableArray([]);
this.newTodo = ko.observable("");
}
addTodo(): void {
const newTodo = this.newTodo();
if (newTodo) {
this.todos.push(new Todo(newTodo));
this.newTodo("");
}
}
removeTodo(todo: Todo): void {
this.todos.remove(todo);
}
}
このコードは、次の機能を提供します。
- Todo アイテムを削除できます。
- Todo アイテムを完了または未完了としてマークできます。
- Todo アイテムのリストを表示します。
Knockout.js コンポーネントを使用して、Todo アイテムと Todo リストを個別にカプセル化することができます。これにより、コードをよりモジュール化し、保守しやすくなります。
// Todo アイテムを表す Knockout.js コンポーネント
ko.components.register('todo-item', {
template: `
<li>
<input type="checkbox" data-bind="checked: completed" />
<span data-bind="text: name"></span>
<button data-bind="click: $parent.removeTodo">削除</button>
</li>
`,
viewModel: {
name: ko.observable<string>(),
completed: ko.observable<boolean>(),
removeTodo: (todo: TodoViewModel) => {
todo.removeTodo(this);
}
}
});
// Todo リストを表す Knockout.js コンポーネント
ko.components.register('todo-list', {
template: `
<ul data-bind="foreach: todos">
<todo-item data-bind="todo: $data"></todo-item>
</ul>
<input type="text" data-bind="value: newTodo, enter: addTodo" placeholder="新しい Todo を入力...">
`,
viewModel: TodoViewModel
});
この例では、todo-item
という名前のコンポーネントと todo-list
という名前のコンポーネントを定義しています。todo-item
コンポーネントは Todo アイテムを表し、todo-list
コンポーネントは Todo アイテムのリストを表します。
Knockout.js モジュールを使用して、Todo アプリケーションのコードをより組織化することができます。モジュールを使用すると、コードをファイルに分割し、コードをより読みやすく、保守しやすくなります。
// TodoViewModel モジュール
export class TodoViewModel {
todos: KnockoutObservableArray<Todo>;
newTodo: KnockoutObservable<string>;
constructor() {
this.todos = ko.observableArray([]);
this.newTodo = ko.observable("");
}
addTodo(): void {
const newTodo = this.newTodo();
if (newTodo) {
this.todos.push(new Todo(newTodo));
this.newTodo("");
}
}
removeTodo(todo: Todo): void {
this.todos.remove(todo);
}
}
// Todo モジュール
export class Todo {
name: string;
completed: boolean;
constructor(name: string) {
this.name = name;
this.completed = false;
}
}
// Main モジュール
import { TodoViewModel } from './todo-view-model';
const viewModel = new TodoViewModel();
ko.applyBindings(viewModel);
この例では、todo-view-model.ts
という名前のファイルと todo.ts
という名前のファイルを作成しています。todo-view-model.ts
ファイルには TodoViewModel
クラスが含まれ、todo.ts
ファイルには Todo
クラスが含まれます。main.ts
ファイルでは、TodoViewModel
クラスのインスタンスを作成し、DOM にバインドします。
TypeScript クラスの装飾子を使用する
TypeScript クラスの装飾子を使用して、Knockout.js の observable プロパティと computed プロパティを自動的に生成することができます。これにより、コードをより簡潔に記述することができます。
// @observable と @computed デコレータを使用する TodoViewModel クラス
@observable
class TodoViewModel {
todos: Todo[] = [];
newTodo: string = "";
@computed
get remainingTodos(): number {
return this.todos.filter(todo => !todo.completed).length;
}
addTodo(): void {
if (this.newTodo) {
this.todos.push({
name: this.newTodo,
completed: false
});
this.newTodo = "";
}
}
removeTodo(todo: Todo): void {
this.todos.splice(this.todos.indexOf(todo), 1);
}
}
//
knockout.js typescript