インターフェイス【個人学習まとめ】
インターフェイスとは
オブジェクトの構造を定義するのに特化した機能。
インターフェイスの宣言
interface Pet {
name: string;
age: number;
}
実際にインターフェイスを用いた型指定の例。
変数pochi
にPet
インターフェイスを指定する。
let pochi: Pet = {
name: "pochi",
age: 3
}
次の書き方はエラーになる。
//型 'string' を型 'Pet' に割り当てることはできません。
pochi = "tama";
//型 'string' を型 'number' に割り当てることはできません。
pochi = {
name: "pochi",
age: "3"
}
(余談)シグネチャって?
関数やメソッドの型情報を定義するときに使われる。
例えば関数シグネチャとは・・・
その関数が受け取る引数の型や戻り値の型を示す。
function greet(name:string):string;
このシグネチャは、greet
という関数がstring
型のname
を受け取り、string
型を返却することを示す。
インターフェイスとメソッド
インターフェイスを使うと、オブジェクトが実装すべきメソッドも定義できる。
プロパティ名の末尾に?
を付けることによって、オプショナルプロパティ=省略可能なプロパティを設定できる。
さらに、readonrly
をプロパティ名の前につけることによって、読み取り専用のプロパティを設定できる。
interface PetWithMethod {
name: string;
age: number;
cry(word: string): void;
favorite(word: string): void;
//オプショナルプロパティ
hair_color?: string;
readonly owner: string;
}
const tama: PetWithMethod = {
name: "tama",
age: 3,
cry(word) {
console.log(word);
},
favorite(word) {
console.log(word)
},
//hair_color は省略
owner: "わたし"
}
tama.cry("にゃんにゃん")
tama.favorite("好きなことは寝ること")
//tama.owner = '父親'; //読み取り専用プロパティであるため、'owner' に代入することはできません。
インデックスシグネチャ
プロパティの名前がわからないけれど、プロパティの値の型がわかっている場合などに使用される。
オブジェクトのプロパティが事前にわかる場合は型定義していた方が安全に利用できる。
動的にプロパティ名が変わる場合(APIからデータ取得)に、プロパティ名が事前に定義されていないオブジェクトに型を付ける場合に適している。
構文[キーの名前(任意):キーの型]: 値の型
任意の名前をプロパティを追加でき、その追加したプロパティの値はnumber
型であるFoodStock
というインデックスシグネチャを用意。
interface FoodStock {
[i: string]: number;
}
``
定数`food`を用意し、型は`FoodStock`とする。
```ts
const food: FoodStock = {} //初期化
food
の値にnumber
型を代入できるが、string
型はFoodStock
の型違反となりエラーになる。
food.rice = 5;
food.apple = 10;
food.meat = "いっぱい"; //エラー:型 'string' を型 'number' に割り当てることはできません。
インデックスシグネチャに明示的なプロパティを混在
インデックスシグネチャに明示的なプロパティを混在させることもできる
interface FoodStockWithExplicitProperty {
egg: number; //明示的な egg プロパティ
[i: string]: number;
}
const food2: FoodStockWithExplicitProperty = {
egg: 6 //明示的なプロパティのため必須。もし書かないとエラーになる:プロパティ 'egg' は型 '{}' にありませんが、型 'FoodStockWithExplicitProperty' では必須です。
}
food2.rice = 5
food.apple = 10;
インターフェイスの拡張
拡張元のインターフェイス
interface Car {
speed: number;
}
NomalCarはCarを拡張したインターフェイス
interface NormalCar extends Car {
engineType: string;
volume: number;
}
const MyCar: NormalCar = {
speed: 240,
engineType: "V1",
volume: 4000
}
拡張元の Car に存在する speed
プロパティが存在していないためエラーとなる
// プロパティ 'speed' は型 '{ engineType: string; volume: number; }' にありませんが、型 'NormalCar' では必須です。
const ParentCar: NormalCar = {
engineType: "V4",
volume: 3000
}
オーバーライド
ある機能の動作を上書きして別の機能や動作に置き換える。
拡張して新たなインターフェイスを作成した場合、元のインターフェイスに存在するプロパティをオーバーライドできる。
interface Car2 {
speed: number;
model: string | null;
}
interface FamiryCar extends Car2 {
engineType: string;
model: string; //modelをオーバーライド
}
ただし、元のインターフェイスと互換性が無ければならない。
ここはコメントアウト
interface FriendCar extends Car2 {
engineType: string;
model: number; //modelをオーバーライドしようとしても元の型`string | null`と`number`は互換性がないためエラー
}
複数のインターフェイスの拡張
インターフェイスの拡張は複数のインターフェイスを基にして行うことができる。
interface People {
birthDate: Date;
prefecture: string;
}
interface Hobby {
hobbies: string[];
}
interface Office {
companyName: string;
companyTel: string;
}
複数インターフェイスを拡張をしてみる。
interface Personal extends People, Hobby {
name: string;
}
interface WorkingPerson extends Personal, Office {
kinzokuYear: number;
tsukinHoho?: "train" | "car" | "walk";
}
const me: Personal = {
name: "Mike",
birthDate: new Date("2024/01/01"),
prefecture: "Tokyo",
hobbies: ["tennis", "cokking", "chess"],
};
const brother: WorkingPerson = {
name: "Aniki",
birthDate: new Date("2020/01/01"),
prefecture: "Hokkaido",
hobbies: ["basketball", "game", "chess"],
companyName: "株式会社○○",
companyTel: "999-9999-9999",
kinzokuYear: 3,
tsukinHoho: "train"
};
const sister: WorkingPerson = {
name: "Aneki",
birthDate: new Date("2022/01/01"),
prefecture: "Okinawa",
hobbies: ["cafe", "chess"],
companyName: "株式会社xx",
companyTel: "999-9999-9999",
kinzokuYear: 2,
};
Discussion