関数型の部分型関係のうち最も簡単なのは、返り値の型により部分型関係が発生する場合です。 SがTの部分型ならば、同じ引数リストに対して(引数リスト) => S という関数型は(引数リスト) => T という関数型の部分型になります。
出典:プロを目指す人のためのTypeScript入門 p161
/*
* Function Subtyping releation
*/
type Human = {
name: string;
age: number;
};
type User = {
name: string;
age: number;
isUser: boolean;
}
type SuperType = (name: string, age: number) => Human;
type SubType = (name: string, age: number) => User;
const createHuman: SuperType = (name, age) => {
return {name, age};
}
const createUser: SubType = (name, age) => {
return {name, age, isUser: true};
}
const useFunc = (f: SuperType, name: string, age: number) => {
console.log(f(name, age));
}
useFunc(createHuman, "Taro", 20);
useFunc(createUser, "Taro", 20);
オブジェクトはプリミティブの部分型ではないので以下はコンパイルエラーになります。
/*
* コンパイルエラー
*/
type T = (name: string) => string;
type S = (name: string) => {name: string, foo: string};
const tFunc: T = (name) => {
return name;
}
const sFunc: S = (name) => {
return {name, foo: 'bar'};
}
const useFunc2 = (f: T, name: string) => {
console.log(f(name));
}
// コンパイルエラー
// 型 'S' の引数を型 'T' のパラメーターに割り当てることはできません。
// 型 '{ name: string; foo: string; }' を型 'string' に割り当てることはできません。
useFunc2(sFunc, 'Taro'); // <--- コンパイルエラー
引数の型が違う関数同士の部分型関数に進みましょう。型Sが型Tの部分型であるとき、「Tを引数に受け取る関数」の型は「Sを引数に受け取る関数」の型の部分型となります。
/*
* Function Sub typing
*/
type Human = {
name: string;
age: number;
};
type User = {
name: string;
age: number;
isUser: boolean;
}
type SuperType = (name: string, age: number) => Human;
type SubType = (name: string) => User;
const createHuman: SuperType = (name, age) => {
return {name, age};
}
const createUser: SubType = (name) => {
return {name, age: 20, isUser: true};
}
const useFunc = (f: SuperType, name: string, age?: number) => {
console.log(f(name, age ?? -1))
}
useFunc(createUser, "Taro");