TypeScript文法(基礎編) 関数の作り方

# 関数とは何か？

TypeScriptに限らず、プログラミング言語のほとんどには、
関数という概念があります。

変数が、**値**を使いまわしたり、名付けをしたりすることができる箱であるなら、
関数は、**処理**を使いまわしたり、名付けをしたりすることができる箱です。

プログラムをわかりやすく分割して、
処理ごとに命名をして、
見通しをよくすることができるため、
特に大規模のプロジェクトなどでは、
関数を使うことはもはや必須です。


# TypeScriptの関数定義

TypeScriptの関数宣言は、
**function 関数名(引数リスト): 返り値の型 { 処理の中身 }という形の構文で
表されます。**

```ts
function test(arg1: number, arg2: number): number[] {
    const val = [];
    val.push(arg1);
    val.push(arg2);
    return val
}

console.log(test(10, 30)) // [10, 30] と表示される
```



引数の型を間違えたり、引数の数を間違えると、
コンパイルエラーとなります。

```ts
//下記の2つはエラー
test("10", "30")
test(10)
```

returnによって、
関数の実行が終了して与えられた式が関数の返り値となります。
そのため、returnよりあとに書かれた部分は、
実行されません。

```ts
function test(arg1: number, arg2: number): number[] {
    const val = [];
    val.push(arg1);
    val.push(arg2);
    return val
    console.log('test') // 実行されない
}

console.log(test(10, 30)) // [10, 30] と表示される
```

そして、返り値にも型チェックが行われ、
test関数の返り値は、number[]でなければなりません。

返り値がない関数の宣言は、
void型を設定する。

```ts
function test(arg1: number, arg2: number): void {
    const val = [];
    val.push(arg1);
    val.push(arg2);
    console.log('test')
}

test(10, 30)
```

関数の定義の仕方としては、
上記の他に、変数に入れる方法もある。

```ts
const functest = function (arg1: number, arg2: number): void {
    const val = [];
    val.push(arg1);
    val.push(arg2);
    console.log('test')
}

functest(10, 30)
```

変数に代入する場合は、**function (引数): 返り値の型 {}というふうに定義する。**
関数名は省略できる。

# アロー関数

TypeScriptとかJavaScriptの関数定義において、
正直functionなどと書いて定義することは稀で、
ほとんどの場合こちらのアロー関数の形式で定義されている気がする。


構文としては、**(引数): 返り値の型 => {}** とする。

```ts
const functest = (arg1: number, arg2: number): void => {
    const val = [];
    val.push(arg1);
    val.push(arg2);
    console.log('test')
}

functest(10, 30)
```

返り値をいきなり返すような、
簡単なアロー関数であれば、更に省略することができる。

```ts
const simplefunc = (arg1: number, arg2: number): number => arg1 + arg2
console.log(simplefunc(10, 30))
```
これは、**(arg1: number, arg2: number): number => { return arg1 + arg2 }** と同様である。

オブジェクトを返す場合は、{}と書いても、
アロー関数の中身を囲む{}とみなされてしまうので、
()で囲む必要がある。


```ts
type simpleObj = {
    val1: number
}
//正しい
const simplefunc = (arg1: number, arg2: number): simpleObj => ({ val1: arg1 + arg2 })

//エラー
const simplefunc = (arg1: number, arg2: number): simpleObj => { val1: arg1 + arg2 }

console.log(simplefunc(10, 30))
```

# オプショナル引数

通常の関数定義の場合、
引数に定義されたものを渡さなければエラーとなりますが、
場合によって何も渡さずに処理したいこともあります。

その際、使用するのが、**オプショナル引数や、デフォルト値の指定です。**

オプショナル引数は、**引数名?: 型**と定義します。

```ts
const simplefunc = (arg1: number, arg2?: number): number => {
    console.log(arg1)
    console.log(arg2)
    return arg1
}

console.log(simplefunc(10))
```

これを実行してみるとわかるが、
オプショナル引数が省略された場合、
その引数にはundefinedが入る。

そのため、undefinedが混入することを避けたい場合、
デフォルト値を使ったほうがいいだろう。

デフォルト値は、**引数名: 型 = 値**と定義する

```ts
const simplefunc = (arg1: number, arg2: number = 20): number => {
    console.log(arg1)
    console.log(arg2)
    return arg1 + arg2
}

console.log(simplefunc(10))
```
ちなみに、上記のコードをオプショナル引数として、
実行すると、arg2がundefinedになる可能性があると、
エラーになる。

デフォルト値を指定した場合、
引数にundefinedを渡すこともできるが、
その場合、デフォルト値に変換される。

```ts
const simplefunc = (arg1: number, arg2: number = 20): number => {
    console.log(arg1)
    console.log(arg2) //20と表示される
    return arg1 + arg2
}

console.log(simplefunc(10, undefined))
```

# コールバック関数

コールバック関数とは、関数の引数として渡される関数のことで、
これに対しコールバック関数を引数として受け取る関数を高階関数という。

代表的な高階関数としては、mapやfilterなどがある。

```ts
type User = { name: string, email: string }
const users: User[] = [
    { name: "Alice", email: "alice@test.com" },
    { name: "Mike", email: "mike@test.com" }
]
const callbackfunc = (user: User): string => {
    return user.name
}
const func1 = users.map(callbackfunc)
console.log(func1)//["Alice", "Mike"] と表示される
```

map関数に渡されている、callbackfuncがコールバック関数にあたり、
高階関数のmapは、与えられた関数を配列のすべての要素に対して呼び出して、
新しい配列を生成する

# ジェネリクス

ジェネリクスとは、何かと考えると、
下記の記事にあるような感じになると思われる。

> 使われるまで型が決まらないようないろいろな型の値を受け入れられる機能を作るときに使います。ジェネリクスは日本語で総称型と呼ばれることもあります
https://future-architect.github.io/typescript-guide/generics.html



型引数のように、呼び出す側で型とかを指定できるような記法で、
関数の場合、<型引数>(引数): 返り値というふうに定義する。

```ts
function func1<T>(arg1: T): T[] {
    const arr: T[] = []
    arr.push(arg1)
    return arr
}

console.log(func1<number>(10)) //[10]と表示される
```

呼び出すときは、関数<型引数>(引数)で呼び出す。
呼び出すときに、型を指定できるので、

```ts
function func1<T>(arg1: T): T[] {
    const arr: T[] = []
    arr.push(arg1)
    return arr
}

console.log(func1<string>('arr')) //['arr']と表示される
```
とかもできる