クラスの継承
extends
class Animal {
constructor(public name: string) {}
speak(): void {
console.log(`${this.name}が鳴いています`);
}
}
class Dog extends Animal {
constructor(name: string, public breed: string) {
super(name); // 親のコンストラクタ呼び出し
}
// オーバーライド
speak(): void {
console.log(`${this.name}がワンワン鳴いています`);
}
// 新しいメソッド
fetch(): void {
console.log(`${this.name}がボールを取ってきます`);
}
}
const dog = new Dog("ポチ", "柴犬");
dog.speak(); // "ポチがワンワン鳴いています"
dog.fetch(); // "ポチがボールを取ってきます"
super キーワード
class Vehicle {
constructor(public speed: number) {}
describe(): string {
return `速度: ${this.speed}km/h`;
}
}
class Car extends Vehicle {
constructor(speed: number, public brand: string) {
super(speed);
}
// 親のメソッドを呼び出して拡張
describe(): string {
return `${this.brand} - ${super.describe()}`;
}
}
const car = new Car(120, "トヨタ");
console.log(car.describe()); // "トヨタ - 速度: 120km/h"
インターフェース
基本的なインターフェース
interface User {
id: number;
name: string;
email: string;
age?: number; // オプショナル
readonly createdAt: Date; // 読み取り専用
}
const user: User = {
id: 1,
name: "太郎",
email: "taro@example.com",
createdAt: new Date()
};
インターフェースの拡張
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
employeeId: number;
department: string;
}
// 複数のインターフェースを拡張
interface Manager extends Employee {
subordinates: Employee[];
}
const manager: Manager = {
name: "太郎",
age: 40,
employeeId: 1,
department: "開発部",
subordinates: []
};
クラスへの実装
interface Printable {
print(): void;
}
interface Serializable {
serialize(): string;
}
// 複数のインターフェースを実装
class Document implements Printable, Serializable {
constructor(public title: string, public content: string) {}
print(): void {
console.log(`${this.title}\n${this.content}`);
}
serialize(): string {
return JSON.stringify({ title: this.title, content: this.content });
}
}
関数型インターフェース
interface MathOperation {
(a: number, b: number): number;
}
const add: MathOperation = (a, b) => a + b;
const multiply: MathOperation = (a, b) => a * b;
// コールシグネチャとプロパティの両方
interface Counter {
(start: number): number;
interval: number;
reset(): void;
}
ジェネリクス
ジェネリッククラス
class Container<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
get(index: number): T | undefined {
return this.items[index];
}
getAll(): T[] {
return [...this.items];
}
}
const stringContainer = new Container<string>();
stringContainer.add("hello");
stringContainer.add("world");
const numberContainer = new Container<number>();
numberContainer.add(1);
numberContainer.add(2);
ジェネリックインターフェース
interface Repository<T> {
findById(id: number): T | null;
findAll(): T[];
save(item: T): void;
delete(id: number): boolean;
}
interface User {
id: number;
name: string;
}
class UserRepository implements Repository<User> {
private users: User[] = [];
findById(id: number): User | null {
return this.users.find(u => u.id === id) || null;
}
findAll(): User[] {
return [...this.users];
}
save(user: User): void {
this.users.push(user);
}
delete(id: number): boolean {
const index = this.users.findIndex(u => u.id === id);
if (index >= 0) {
this.users.splice(index, 1);
return true;
}
return false;
}
}
制約付きジェネリクス
interface HasId {
id: number;
}
// T は id プロパティを持つ必要がある
function findById<T extends HasId>(items: T[], id: number): T | undefined {
return items.find(item => item.id === id);
}
interface User extends HasId {
name: string;
}
interface Product extends HasId {
title: string;
price: number;
}
const users: User[] = [{ id: 1, name: "太郎" }];
const products: Product[] = [{ id: 1, title: "本", price: 1500 }];
findById(users, 1); // User | undefined
findById(products, 1); // Product | undefined
ユーティリティ型
Partial と Required
interface User {
id: number;
name: string;
email: string;
}
// すべてのプロパティをオプショナルに
type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; }
// すべてのプロパティを必須に
interface Config {
debug?: boolean;
timeout?: number;
}
type RequiredConfig = Required<Config>;
// { debug: boolean; timeout: number; }
Pick と Omit
interface User {
id: number;
name: string;
email: string;
password: string;
}
// 特定のプロパティだけ選択
type PublicUser = Pick<User, "id" | "name" | "email">;
// { id: number; name: string; email: string; }
// 特定のプロパティを除外
type UserWithoutPassword = Omit<User, "password">;
// { id: number; name: string; email: string; }
Record
// キーと値の型を指定したオブジェクト型
type UserRoles = Record<string, string[]>;
const roles: UserRoles = {
admin: ["read", "write", "delete"],
user: ["read"],
guest: []
};
// リテラル型と組み合わせ
type Status = "pending" | "approved" | "rejected";
type StatusMessages = Record<Status, string>;
const messages: StatusMessages = {
pending: "審査中",
approved: "承認済み",
rejected: "却下"
};
Readonly と ReadonlyArray
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
// { readonly id: number; readonly name: string; }
const user: ReadonlyUser = { id: 1, name: "太郎" };
// user.name = "花子"; // エラー
// 読み取り専用配列
const numbers: ReadonlyArray<number> = [1, 2, 3];
// numbers.push(4); // エラー
ポリモーフィズム
abstract class Shape {
abstract area(): number;
}
class Rectangle extends Shape {
constructor(public width: number, public height: number) {
super();
}
area(): number {
return this.width * this.height;
}
}
class Circle extends Shape {
constructor(public radius: number) {
super();
}
area(): number {
return Math.PI * this.radius ** 2;
}
}
// 型安全なポリモーフィズム
function printArea(shape: Shape): void {
console.log(`面積: ${shape.area()}`);
}
printArea(new Rectangle(10, 5)); // "面積: 50"
printArea(new Circle(7)); // "面積: 153.93..."
実践例:DIコンテナ
interface Logger {
log(message: string): void;
}
interface Database {
query(sql: string): unknown[];
}
class ConsoleLogger implements Logger {
log(message: string): void {
console.log(`[LOG] ${message}`);
}
}
class PostgresDatabase implements Database {
query(sql: string): unknown[] {
console.log(`Executing: ${sql}`);
return [];
}
}
// DIコンテナ
class Container {
private services = new Map<string, unknown>();
register<T>(key: string, service: T): void {
this.services.set(key, service);
}
resolve<T>(key: string): T {
const service = this.services.get(key);
if (!service) {
throw new Error(`Service not found: ${key}`);
}
return service as T;
}
}
// 使用例
const container = new Container();
container.register<Logger>("logger", new ConsoleLogger());
container.register<Database>("db", new PostgresDatabase());
class UserService {
constructor(
private logger: Logger,
private db: Database
) {}
getUsers(): void {
this.logger.log("Fetching users");
this.db.query("SELECT * FROM users");
}
}
const userService = new UserService(
container.resolve<Logger>("logger"),
container.resolve<Database>("db")
);
userService.getUsers();
まとめ
extendsでクラスを継承implementsでインターフェースを実装- インターフェースで契約を定義
- ジェネリクスで再利用可能な型を作成
extends制約でジェネリクスに制限Partial,Pick,Omitなどのユーティリティ型- 抽象クラスとインターフェースでポリモーフィズム
これでTypeScript基礎は完了です。次は実践編でファイル操作やエラー処理を学びましょう。