1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[TypeScript] 関数の型定義をマスターしよう!

Last updated at Posted at 2024-04-22

はじめに

前回に続き、関数の利用についてまとめました。

【目次】

まずは基本的な型宣言をマスターしよう!
オブジェクト型の型宣言をマスターしよう!
関数の型定義をマスターしよう! ←🈁
配列をマスターしよう!
インターフェースをマスターしよう!
クラスを使いこなそう!
型修飾子についての理解を深めよう!
ジェネリックをマスターしよう!
独自の構文拡張をマスターしよう!


関数に関する前提知識

JavaScriptとTypeScriptでは以下の違いがあります。

  • JavaScriptは引数の数が任意でも呼び出し可
    • 引数がundefindを取り得る
  • TypeScriptは引数の数を厳密にチェックしている
    • 引数の数が異なる場合、型エラーが発生する

JavaScript

function fn (input1, input2) {
  console.log(input1, input2)
}

fn("hoge")

// [LOG]: "hoge",  undefined 

TypeScript

function fn (input1: string, input2: string) {
  console.log(input1, input2)
}

fn("hoge") //NG: Expected 2 arguments, but got 1.

引数の型アサーション

引数名: 型とすることで引数の型定義が可能です。

function fn(input: string) {
  console.log(input.toLocaleUpperCase)
}

// OK
fn("hoge")

// NG: Argument of type 'number' is not assignable to parameter of type 'string'.
fn(1234)

オプションパラメータ

引数をオプショナル(省略可能)としたい場合は引数名の末尾に ? をつけることで、TypeScriptにオプショナルな引数であることを伝えることができます。

function fn (input1: string, input2?: string) {
  console.log(input1, input2)
}

//OK: "hoge",  undefined 
fn("hoge")

//OK: "hoge",  "foo" 
fn("hoge", "foo")

デフォルトパタメータ

引数名: 型 = デフォルト値とすることで、引数に対してデフォルト値を設定することができます。

function fn (input1: string, input2:string = "foo" ) {
  console.log(input1, input2)
}

//OK: "hoge",  "foo" 
fn("hoge")

//OK: "hoge",  "buz" 
fn("hoge", "buz)

レストパラメータ

引数として、任意の長さの配列を受け取りたい場合はレストパラメータ(...引数)を使用する。
レストパラメータを用いる場合は、そのパラメータが取りうるデータ型[]を型指定する。

function fn (...inputs: string[]) {
  for(let input of inputs) {
    console.log(input)
  }
}

//OK: "hoge"
fn("hoge")

//OK: "hoge", "foo", "buz"
fn("hoge", "foo", "buz")

戻り値の型

パラメータの後に : 型を指定することで、関数の戻り値を定義できますl

// OK
function fn (input: string): number { 
  console.log(`called fn with ${input}`)
  
  return input.length
}

// NG: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
function fn (input: string): number {
  console.log(`called fn with ${input}`)
}


関数の型宣言

JavaScriptでは、関数を値として渡すことができます。
TypeScriptでは、関数に対してデータ型を定義することができます。

// 引数なし: string型の戻り値を返す
let nothingInputFn: () => string;

// string型の引数を1つ受け取り、number型の戻り値を返す
let stringInputFn: (input: string) => number

これらはコールバック関数を表す際によく利用されます。

const songs = ["Hello", "MyName", "is", "Code", "Taro"]

function runSongs(phrases: string[], song: (lyrics: string) => string) {
    for(let phrase of phrases) {
        console.log(song(phrase))
    }
}

// (lyrics: string) => string に適合
function songAt(lyrics: string) {
    return `${lyrics}~`;
}

runSongs(songs, songAt);

// "Hello~", "MyName~", "is~", "Code~", "Taro~" 

戻り値の型

特徴的な戻り値のデータ型についてご紹介します。

void

戻り値がないことを示す。

function fnA(input: string): void {
    console.log(input);
}

// voidの戻り値は変数に格納できない(戻り値を利用できない)
let buz: undefined = fnA();

never

関数の実行後に呼び出し側のコードが実行されないことを意味する(例外処理などに利用)

function throwException(message: string): never {
    throw new Error(message);
}

console.log("hello")
throwException("エラー発生。");

// ↓以降の処理は実行されない
console.log("World")

オーバーロードシグネチャ

TypeScriptの機能で、ひとつの関数に異なる関数シグネチャを複数もつ関数です。
異なる引数や戻り値のパターンがいくつかある関数をオーバーロード関数と呼びます。

前提

TypeScriptでは、オーバーロード関数は、関数シグネチャと実装シグネチャの2つの部分に分けて書きます。

  • 関数シグネチャ
    • TypeScriptが関数の呼び出しが正しいかチェックするための関数呼び出しパターン
  • 実装シグネチャ
    • 内部ロジック
    • 関数シグネチャと互換性がある形で実装する必要がある。

基本的な宣言

function 関数名 関数シグネチャ1
function 関数名 関数シグネチャ2
function 関数名 すべてのシグネチャを網羅する実装シグネチャ

最後の1行を除く、1, 2行目が関数シグネチャ、
最後の1行が実装ということだけ覚えて読み進めてください。

サンプルコード

function hello(person: string): void;
function hello(persons: string[]): void;
function hello(person: string | string[]): void {
  if (typeof person === "string") {
    console.log(`Hello ${person}`);
  } else {
    console.log(`Hello ${person.join(",")}`);
  }
}

実装シグネチャを見ると、全ての関数シグネチャと互換性がある実装となっていますね。

  • (person: string): void;
  • (persons: string[]): void;
    どちらの形で引数を渡しても問題なく実行できる実装となっている。

他の項目と違って初学者の方は難しいかもしれません。
経験則ですが、規模が大きいプロジェクトなどで複雑な関数を定義しない限りは利用する機会は少ないのではないでしょうか?

ref.


TypeScriptにおけるアロー関数

:pencil: 2024/4/25 追記

後々気がついたのですが、
TypeScriptでは、アロー関数を型アノテーションで記述する場合、引数が1つであってもカッコを省略することができないようです。

javascript

let sampleFn = input => console.log(input);
sampleFn("hoge");

typescript

// NG:
interface Foo {
    fn: input:string => void
}

// OK:
interface Foo {
    fn: (input:string) => void
}

他にもびっくりされる方がいそうなので追記しました。


以上です!
Ruby開発が多いので、やっぱり静的型付けっていいよなと思い始めたこの頃...

次節で配列に関する記事を公開しておりますので、よろしければご覧ください🙏

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?