こんにちは、かつコーチです。
今回は、プログラミング界隈でよく言われるオブジェクト指向についてです。
TypeScriptでもオブジェクト指向の考え方があり、習得する上では重要になってきます。
TypeScriptでは、オブジェクト指向プログラミング(OOP)をサポートしており、
オブジェクトやクラス、インターフェース、継承などの概念を使って、
より柔軟で型安全なコードを作成することが可能です。
以下に、TypeScriptのオブジェクト指向について、
オブジェクトそのものの定義から部分型関係や型引数まで、詳細に解説します。
オブジェクトととはなにか
オブジェクトは、複数のプロパティやメソッド(関数)を持つデータの集合体です。
オブジェクトはキーと値のペアで構成され、複雑なデータを一つの変数として管理できます。
const person = {
name: "John",
age: 30,
greet: () => {
console.log("Hello!");
},
};
この例では、person
というオブジェクトが
name
(文字列)、age
(数値)、greet
(メソッド)の3つのプロパティを持っています。
オブジェクトの型
TypeScriptでは、オブジェクトのプロパティに対して型を定義できます。
これは、オブジェクトが持つプロパティの構造を厳密に定義し、
型安全なコードを書くために重要です。
const person: { name: string; age: number } = {
name: "Alice",
age: 25,
};
person
オブジェクトのname
プロパティは
string
型、age
プロパティはnumber
型であることが指定されています。
インターフェースを使った型定義
TypeScriptでは、インターフェース(interface
)を使ってオブジェクトの型を定義できます。
これにより、複数の場所で同じオブジェクト構造を再利用することが容易になります。
interface Person {
name: string;
age: number;
greet(): void;
}
const person: Person = {
name: "Bob",
age: 28,
greet() {
console.log("Hello, I am Bob");
},
};
インターフェースを使うことで、
Person
型のオブジェクトがどのようなプロパティやメソッドを持つべきかを定義できます。
部分型関係
部分型関係とは、ある型が他の型の一部(サブセット)である場合の関係です。
TypeScriptでは、オブジェクトの型が持つプロパティの構造によって部分型関係が決定されます。
部分型関係を利用することで、あるオブジェクトが、
別のオブジェクト型の期待する部分的な構造を満たしているかどうかを判定できます。
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
const myDog: Dog = {
name: "Max",
breed: "Golden Retriever",
};
この場合、Dog
型はAnimal
型の部分型(name
プロパティを持つ)であり、
Dog
はAnimal
型のプロパティを継承しています。
部分型関係を使うことで、サブクラスがスーパークラスのプロパティやメソッドを拡張しつつ、
互換性を保てます。
型引数をもつ型(ジェネリクス)
TypeScriptでは、ジェネリクス(Generics)を使って、
さまざまな型に対して汎用的なコードを書くことができます。
ジェネリクスは型引数を取ることで、クラスや関数、インターフェースが、
より柔軟に異なる型に対応できるようにします。
function identity<T>(arg: T): T {
return arg;
}
const str = identity<string>("Hello");
const num = identity<number>(42);
この例では、identity
関数が型引数T
を取り、引数の型と返り値の型を汎用的に指定しています。
関数を呼び出す際に、実際の型を指定することができます。
ジェネリクスはクラスやインターフェースでも使えます。
class Box<T> {
contents: T;
constructor(value: T) {
this.contents = value;
}
}
const stringBox = new Box<string>("Hello");
const numberBox = new Box<number>(123);
ジェネリクスを使うことで、同じクラスが異なる型に対して動作する汎用的なデータ構造を定義できます。
配列
配列は、同じ型のデータをまとめて扱うためのデータ構造です。
TypeScriptでは、配列の型を定義する際に、要素の型に[]
をつけて表します。
let numbers: number[] = [1, 2, 3, 4];
let strings: string[] = ["one", "two", "three"];
ジェネリクスを使って配列の型を定義することもできます。
let values: Array<number> = [10, 20, 30];
また、オブジェクトの配列も定義可能です。
interface Person {
name: string;
age: number;
}
let people: Person[] = [
{ name: "John", age: 25 },
{ name: "Jane", age: 30 },
];
分割代入(Destructuring)
TypeScriptでは、オブジェクトや配列のプロパティを分割代入によって取り出すことができます。
これにより、コードが簡潔になり、特定のプロパティだけを取り出すのが簡単になります。
オブジェクトの分割代入
const person = {
name: "Alice",
age: 25,
};
const { name, age } = person;
console.log(name); // "Alice"
console.log(age); // 25
配列の分割代入
const numbers = [1, 2, 3];
const [first, second, third] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(third); // 3
その他の組み込みオブジェクト
TypeScriptは、いくつかの組み込みオブジェクトをサポートしています。
これらは、一般的に利用されるオブジェクトで、標準ライブラリとして提供されています。
Dateオブジェクト
Date
は、日時を管理するためのオブジェクトです。
const now = new Date();
console.log(now.toISOString());
Mathオブジェクト
Math
は、数学的な計算に使われるメソッドを提供するオブジェクトです。
const randomNum = Math.random(); // 0〜1のランダムな数を生成
const rounded = Math.round(4.7); // 四捨五入して5を返す
Promiseオブジェクト
Promise
は、非同期処理を管理するためのオブジェクトです。
const fetchData = (): Promise<string> => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
};
fetchData().then((data) => {
console.log(data); // "Data received"
});
まとめ
TypeScriptにおけるオブジェクト指向の概念では、
オブジェクトの構造や型の定義、部分型関係、
ジェネリクス、配列、分割代入といった重要なポイントが含まれます。
TypeScriptの型システムを活用することで、
オブジェクト指向プログラミングをより型安全かつ柔軟に行うことができ、
複雑なコードも分かりやすく構造化できます。