404 Not Found

404 Not Found


nginx

TypeScript のインターフェース (interface)

インターフェースは、TypeScript がオブジェクトの構造を定義する中核となる手段です。これは「オブジェクトが持つべきプロパティやメソッド」を記述するものであり、実装は提供しません。

1. インターフェースの基本構文

(1) インターフェースを定義する

TYPESCRIPT
interface User {
  name: string;
  age: number;
  email: string;
}

(2) インターフェースの使用方法

TYPESCRIPT
let user: User = {
  name: "Charlie",
  age: 20,
  email: "xiaoming@example.com"
};

(3) 関数の引数としてのインターフェース

TYPESCRIPT
function greet(user: User): string {
  return `Hello,${user.name}!How old are you this year?${user.age} years old。`;
}

console.log(greet({ name: "Diana", age: 22, email: "hong@example.com" }));

出力:

TEXT
Hello,Diana!How old are you this year?22 years old。

(4) インターフェースの記述方法

インターフェースでは、プロパティだけでなく、メソッドのシグネチャも記述できます:

TYPESCRIPT
interface Animal {
  name: string;
  speak(): string;
  move(distance: number): void;
}

let dog: Animal = {
  name: "Wangcai",
  speak() { return "Woof!"; },
  move(distance) { console.log(`${this.name} Moved ${distance}m`); }
};

console.log(dog.speak());   // "Woof!"
dog.move(10);               // "Wangcai Moved 10m"

2. オプションのプロパティと読み取り専用プロパティ

(1) オプション属性 ?

TYPESCRIPT
interface Config {
  host: string;
  port: number;
  debug?: boolean;     // Optional
  timeout?: number;    // Optional
}

// Optional attributes may be omitted.
let config: Config = { host: "localhost", port: 3000 };
let config2: Config = { host: "localhost", port: 3000, debug: true };

(2) 読み取り専用プロパティ readonly

TYPESCRIPT
interface Point {
  readonly x: number;
  readonly y: number;
}

let point: Point = { x: 1, y: 2 };
// point.x = 10;  // ❌ Read-only properties cannot be modified.

(3) ReadonlyArray とインターフェース

TYPESCRIPT
interface TodoList {
  readonly name: string;
  readonly items: readonly string[];   // items Both the array itself and its contents are read-only.
}

let todo: TodoList = {
  name: "Today's Tasks",
  items: ["Write code", "Test", "Deployment"]
};

// todo.items.push("New Task");  // ❌ Read-only arrays cannot be modified.
// todo.name = "Tomorrow's Tasks";     // ❌ Read-only properties cannot be modified.

3. インターフェースの継承 (extends)

インターフェースは、extends を通じて他のインターフェースから継承することができ、これにより型の構成や再利用が可能になります:

(1) 単一継承

TYPESCRIPT
interface Person {
  name: string;
  age: number;
}

interface Employee extends Person {
  employeeId: string;
  department: string;
}

let emp: Employee = {
  name: "Charlie",
  age: 28,
  employeeId: "E001",
  department: "Engineering Department"
};

(2) 多重継承

インターフェースは、同時に複数のインターフェースから継承することができます:

TYPESCRIPT
interface Serializable {
  serialize(): string;
}

interface Loggable {
  log(message: string): void;
}

interface Entity extends Serializable, Loggable {
  id: number;
}

let item: Entity = {
  id: 1,
  serialize() { return JSON.stringify({ id: this.id }); },
  log(message) { console.log(`[${this.id}] ${message}`); }
};

(3) プロパティのオーバーライド

子インターフェースは親インターフェースのプロパティ型を上書きできますが、互換性が保たれている必要があります:

TYPESCRIPT
interface Base {
  data: string | number;
}

interface Derived extends Base {
  data: string;   // ✅ Narrowing — string is a subtype of string | number
}

▶ 例:継承を用いた階層型型の構築

TYPESCRIPT
// Basic Interfaces
interface Shape {
  color: string;
}

// Extension Interface
interface Square extends Shape {
  sideLength: number;
}

interface Circle extends Shape {
  radius: number;
}

// Usage
let square: Square = { color: "Red", sideLength: 10 };
let circle: Circle = { color: "Blue", radius: 5 };

function describeShape(shape: Shape): string {
  return `One${shape.color}the graphic`;
}

console.log(describeShape(square));  // "A red shape"
console.log(describeShape(circle));  // "A blue shape"

出力:

TEXT
A red shape
A blue shape

4. 宣言の統合

インターフェースのユニークな特徴として、同じ名前のインターフェースは、そのプロパティを自動的に統合します:

(1) 基本的なマージ

TYPESCRIPT
interface Window {
  title: string;
}

interface Window {
  count: number;
}

// Equivalent to:
// interface Window {
//   title: string;
//   count: number;
// }

let win: Window = { title: "Main Window", count: 3 };

(2) マージに関するルール

TYPESCRIPT
interface Calculator {
  compute(a: number, b: number): number;
}

interface Calculator {
  compute(a: string, b: string): string;
}

// After the merger compute There are two overloads
let calc: Calculator = {
  compute(a: any, b: any): any {
    return a + b;
  }
};

console.log(calc.compute(1, 2));        // 3
console.log(calc.compute("a", "b"));    // "ab"

(3) 実用例:サードパーティ製型の拡張

TYPESCRIPT
// For the built-in Window Adding Custom Properties to an Interface
interface Window {
  myCustomProperty: string;
}

// It is now safe to use
// window.myCustomProperty = "hello";  // ✅
💡 これが、サードパーティ製ライブラリの型を拡張する際に、type ではなく interface を使う理由です―― type は型ユニオンをサポートしていませんが、interface はサポートしています。


5. インデックス署名とインターフェース

インデックスシグネチャはインターフェースでも使用できます:

TYPESCRIPT
interface StringMap {
  [key: string]: string;
}

let translations: StringMap = {
  hello: "Hello",
  goodbye: "Goodbye",
  thanks: "Thank you"
};

// Add a new key-value pair
translations["sorry"] = "I'm sorry";

インデックス署名と既知の属性が共存する場合、既知の属性の型は互換性がある必要があります:

TYPESCRIPT
interface Config {
  [key: string]: string | number;
  host: string;       // ✅ string is a subtype of string | number
  port: number;       // ✅ number is a subtype of string | number
  // debug: boolean;  // ❌ boolean No string | number subtypes of
}

6. インターフェースと型エイリアスの違い

インターフェースも型もオブジェクト型を定義できますが、以下の違いがあります:

機能 インターフェース タイプ
オブジェクトの種類 ✅ 主な用途 ✅ その他の用途
ステートメントの結合 ✅ 対応 ❌ 非対応
継承 extends & クロス型
ユニオン型 ❌ 直接定義できない type A = B | C
基本型の別名 ❌ 不可 type ID = string
計算プロパティ ❌ 未対応 ✅ 対応
instanceof ✅ クラスが実装している ❌ できません

(1) インターフェースを使用するタイミング

(2) type の使用タイミング

📌 推奨事項: オブジェクト型には interface を、ユニオン型や高度な型に対する演算には type を使用してください。これら2つは互いに排他的ではなく、同じプロジェクト内で併用することができます。


❓ よくある質問

Q interfacetype、どちらを使うべきですか?
A 簡単な目安として、「オブジェクトの型」を定義するには interface を、 「型エイリアス」や「共用型」を定義するには type を使用してください。チームで既に規約が決まっている場合は、それに従ってください。90%のケースでは、この2つは同等ですので、あまり深く考えすぎないでください。
Q インターフェースは、type で定義された型を継承できますか?
A はい。interface extends は、type で定義された任意のオブジェクト型エイリアスを継承できます。逆に、type も、クロス型 & を使用してインターフェースを組み合わせることができます。この2つは完全に相互運用可能です。
Q 宣言の統合にはどのようなリスクがありますか?
A 宣言の統合はインターフェースの機能の一つですが、潜在的なリスクも伴います。つまり、同じ名前の2つのインターフェースに、名前は同じだが型が異なるプロパティが含まれている場合、コンパイルエラーが発生します。実際の開発では、宣言の統合は主にサードパーティ製ライブラリの型定義(.d.ts)を拡張するために使用されます。日常的なコードでは、同じ名前のインターフェースを定義することは避けるべきです。
Q インターフェースで関数型を記述することはできますか?
A はい、できますが、一般的には type を使うほうが自然です。interface Fn { (a: string): number }type Fn = (a: string) => number と同等ですが、後者の方が簡潔で直感的です。関数型には type を使用することをお勧めします。

📖 まとめ

📝 練習問題

  1. 基本問題(難易度 ⭐)Book インターフェース(title、author、pages、isbn?)を定義し、2つのbookオブジェクトを作成して、それらを出力してください。なお、isbnはオプションのプロパティであることに注意してください。
  2. 上級問題(難易度 ⭐⭐)Shape ベースインターフェース(color メソッドと area メソッドを含む)を定義し、次に CircleRectangle を、それぞれ Shape を継承し、独自のプロパティを追加するように定義してください。Shape 型のパラメータを受け取り、area メソッドを呼び出す関数を記述してください。
  3. 課題(難易度:⭐⭐⭐):宣言を使用して、組み込みの Array<T> インターフェースに last(): T | undefined メソッドを追加してください。次に、実際の配列に対してこのメソッドを呼び出し、なぜモジュール宣言が必要なのかを考えてみてください。
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%