👀

関数型の互換性(引数)【個人学習まとめ】

に公開

関数型の互換性(反変)

前回の記事では戻り値の型に関する互換性(共変)を学習しました。
今度は引数の型について学習します。できるだけ単純にするために、戻り値の型に互換性があると仮定して確認してみましょう。

引数の型

実際に確認する前に、引数の型となる 2 種類のインターフェイスPersonTeacherを定義します。

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

interface Teacher extends Person {
  subject: string;
}

TeacherインターフェイスはPersonインターフェイスを拡張しています。
そのため、Teacherがもつプロパティは

  • name
  • age
  • subject

の 3 つになり、TeacherPersonのサブタイプという関係が成立します。

互換性を確認するためにfunction3function4という関数型の変数と確認用の引数を用意します。

let function3 = (person: Person) => {
  console.log("---- function3 ----");
  console.log(`名前:${person.name}`);
  console.log(`年齢:${person.age}`);
};

let function4 = (teacher: Teacher) => {
  console.log("---- function4 ----");
  console.log(`名前:${teacher.name}`);
  console.log(`年齢:${teacher.age}`);
  console.log(`部活:${teacher.subject}`);
};

//確認用の引数
const personTestData: Person = { name: "テスト太郎", age: 10 };
const teacherTestData: Teacher = {
  name: "先生 太郎",
  age: 20,
  subject: "国語",
};

function3の引数はPerson型、function4の引数はTeacher型です。
それぞれ戻り値はありません。

これまでの学習から、Person型とTeacher型は互換性があるのでfunction3function4が代入できるのではないか?と思いますよね。試してみましょう。

エラーとなりました。なぜでしょうか?
function3は引数としてPerson型を受け取る関数ですが、実際にはfunction4の引数Teacher型を受け取る必要があります。
そのため**function4ではPerson型には存在しないsubjectプロパティにアクセスを試みる**ことになりますが、subjectプロパティが存在しないためエラーとなります。

では逆にfunction4function3は代入できるのでしょうか。

エラー無く代入することができます。

function4function3を代入後function4を呼び出す際には、引数としてTeacher型のオブジェクトを渡す必要があります。
この時、function4にはfunction3が代入されているため、実際には**function3Teacher型の引数が渡され**実行されます。
function3に渡される引数Teacherにはfunction3には必要のないsubjectプロパティが存在しますが、function3内部でsubjectにアクセスしていないため、無視されることになります。

さいごに

2つの記事で関数の互換性(共変・反変)について学習しました。
自分なりにかみ砕いて説明したつもりですが、なかなか難しい内容になってしまいました。(要改善な気がします・・・)
難しい内容でしたが「共変・反変」という正しい名前を知ることができ、勉強になりました。
新たな発見にもつながるので、間違いがあればご指摘いただけるとありがたいです!

脚注
  1. 関数型の互換性(戻り値)【個人学習まとめ】 ↩︎

Discussion