関数はfunction
から始まる書き方のものとアロー関数どちらも JavaScript のものと同じように書けます。違いは型を追加するだけです。
ある数値に1
足すだけのplusOne
関数を定義してみます。まずfunction
のほうで書くと、
function plusOne(num: number) {
return num + 1;
}
アロー関数で書くと、
const plusOne = (num: number) => {
return num + 1;
};
のようになります。引数で変数名: 型, 変数名: 型
の形で定義していきます。上記のような関数は単純でだいたい何をしているか分かるので TypeScript が暗黙的に設定した戻り値の型(number
)で済ますしても大丈夫そうですが、もし複雑で他人が見た時にすぐに判断できないような内容になっていると思ったら戻り値も明確にしておくといいと思います。
戻り値は(...引数): 型
のように引数の括弧の後に型を書きます。上記で書いた関数にそれぞれ戻り値情報を足すと、
function plusOne(num: number): number {
return num + 1;
}
const plusOne = (num: number): number => {
return num + 1;
};
という形になります。
引数がobject
のように単純ではないけれど、ある程度制約を持たせたい(foo
というプロパティを持っている構造体を受け取ってその構造体を返したい)ような場合に便利です。ジェネリックは関数名のあとに<T, U>
のような感じで定義できるもので、これにより型定義を柔軟にすることができます。
interface A {
value: number;
}
interface B extends A {}
interface C extends A {}
function plusOne<T extends A>(obj: T): T {
obj.value = obj.value + 1;
return obj;
};
const b: B = {value: 1};
const c: C = {value : 2}
plusOne(b);
plusOne(c);
extends
を使うことでT
はA
を持っている、またはA
に属していなければいけないというような制約付けができます。つまり、plusOne({foo: 1})
というなものはvalue
プロパティがないので型エラーになります。
また、上記では動的にT
の型を設定しています。
plusOne(b)
でb
が渡ることで(obj: T)
が(obj: B)
ということになります。
(obj: B)
からfunction plusOne<B>(obj: B)
とジェネリクスが埋まり
- つまり、
function plusOne<B>(obj: B): B
のように解決されます。もちろんジェネリクスは自分で設定することもできます。その場合は関数呼び出しの名前のあとにジェネリクスを設定します。
plusOne<A>(b);
ただし、このようにジェネリクスを自分で設定できるのはfunction
から書く記法だけです。アロー関数の場合自分でジェネリクスを設定するにはキャストが必要ですが、以下のようにジェネリクスなアロー関数を定義することはできます。
const plusOne = <T extends A>(obj: T): T {
obj.value = obj.value + 1;
return obj;
};
動的の利点の1つにどのプロパティ値を受け取ったか分かるというのがあると思います。
interface A {
str: string;
num: number;
}
function getProp<T extends A, P extends keyof T>(obj: T, prop: P): T[P] {
return obj[prop];
};
const a: A = {
str: 'a',
num: 1,
}
getProp(a, 'str');
getProp(a, 'num');
それぞれ戻り値がgetProp(a, 'str')
とした時はstring
、getProp(a, 'num')
とした時はnumber
になります。これはP extends keyof T
(つまりここではP extends 'str' | 'num'
)のP
に実際に指定されたプロパティの値を設定してくれることで、T[P]
がT['str']
,T['num']
と解決してくれるためです。
例えばこれは、getProp<A, keyof A>(a, 'num')
と使ったらどうなるでしょう。これはP
にすべてのプロパティが来る可能性がでてくるので、オブジェクトの値の型の Union 、今回であればstring | number
という戻り型になります。