関数についてさらに詳しく

関数は、ローカル関数、別のモジュールからインポートされた関数、またはクラスのメソッドなど、あらゆるアプリケーションの基本的な構成要素です。それらは値でもあるため、他の値と同様に、TypeScript には関数の呼び出し方法を記述する多くの方法があります。関数を記述する型を記述する方法を学びましょう。

関数型式

関数を記述する最も簡単な方法は、関数型式を使用することです。これらの型は構文的にアロー関数に似ています。

ts
function greeter(fn: (a: string) => void) {
fn("Hello, World");
}
 
function printToConsole(s: string) {
console.log(s);
}
 
greeter(printToConsole);
Try

構文 (a: string) => void は、「`a` という名前の 1 つの引数を持つ関数で、型は `string` であり、戻り値がない」という意味です。関数宣言と同様に、引数の型が指定されていない場合、暗黙的に `any` となります。

引数名は**必須**であることに注意してください。関数型 `(string) => void` は、「`string` という名前の引数(型は `any`)を持つ関数」という意味です!

もちろん、型エイリアスを使用して関数型に名前を付けることができます。

ts
type GreetFunction = (a: string) => void;
function greeter(fn: GreetFunction) {
// ...
}
Try

呼び出しシグネチャ

JavaScript では、関数は呼び出し可能であることに加えて、プロパティを持つことができます。ただし、関数型式構文ではプロパティの宣言はできません。プロパティを持つ呼び出し可能なものを記述する場合は、オブジェクト型に呼び出しシグネチャを記述できます。

ts
type DescribableFunction = {
description: string;
(someArg: number): boolean;
};
function doSomething(fn: DescribableFunction) {
console.log(fn.description + " returned " + fn(6));
}
 
function myFunc(someArg: number) {
return someArg > 3;
}
myFunc.description = "default description";
 
doSomething(myFunc);
Try

関数型式と比べて構文がわずかに異なることに注意してください。引数リストと戻り値の型の間には `=>` ではなく `:` を使用します。

コンストラクトシグネチャ

JavaScript 関数は、`new` 演算子を使用して呼び出すこともできます。TypeScript は、通常新しいオブジェクトを作成するため、これらをコンストラクターと呼びます。`new`キーワードを呼び出しシグネチャの前に追加することで、コンストラクトシグネチャを記述できます。

ts
type SomeConstructor = {
new (s: string): SomeObject;
};
function fn(ctor: SomeConstructor) {
return new ctor("hello");
}
Try

JavaScript の `Date` オブジェクトなどの一部のオブジェクトは、`new` を使用してまたは使用せずに呼び出すことができます。呼び出しシグネチャとコンストラクトシグネチャは、同じ型に任意に組み合わせることができます。

ts
interface CallOrConstruct {
(n?: number): string;
new (s: string): Date;
}
Try

ジェネリック関数

入力の型が出力の型に関連付けられている関数、または2つの入力の型が何らかの方法で関連付けられている関数を記述することは一般的です。配列の最初の要素を返す関数を考えてみましょう。

ts
function firstElement(arr: any[]) {
return arr[0];
}
Try

この関数はその役割を果たしますが、残念ながら戻り値の型は `any` です。関数が配列要素の型を返す方が良いでしょう。

TypeScript では、2つの値間の対応関係を記述する必要がある場合にジェネリクスが使用されます。これは、関数シグネチャに型パラメーターを宣言することで行います。

ts
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0];
}
Try

この関数に型パラメーター `Type` を追加し、2つの場所でそれを使用することで、関数の入力(配列)と出力(戻り値)の間にリンクを作成しました。これで、呼び出すとより具体的な型が出力されます。

ts
// s is of type 'string'
const s = firstElement(["a", "b", "c"]);
// n is of type 'number'
const n = firstElement([1, 2, 3]);
// u is of type undefined
const u = firstElement([]);
Try

推論

このサンプルでは `Type` を指定する必要がなかったことに注意してください。型は TypeScript によって推論されました(自動的に選択されました)。

複数型パラメーターも使用できます。たとえば、`map` のスタンドアロンバージョンは次のようになります。

ts
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
return arr.map(func);
}
 
// Parameter 'n' is of type 'string'
// 'parsed' is of type 'number[]'
const parsed = map(["1", "2", "3"], (n) => parseInt(n));
Try

この例では、TypeScript は `Input` 型パラメーターの型(指定された `string` 配列から)と `Output` 型パラメーターの型(関数式の戻り値 `number` から)の両方を推論できます。

制約事項

あらゆる種類の値で動作する汎用的な関数をいくつか記述しました。2つの値を関連付ける必要がある場合がありますが、特定の値のサブセットでのみ操作できます。この場合、制約を使用して、型パラメーターが受け入れることができる型の種類を制限できます。

2つの値のうち、より長い方を返す関数を作成しましょう。そのためには、数値である`length`プロパティが必要です。`extends`句を記述することで、型パラメーターをその型に制約します。

ts
function longest<Type extends { length: number }>(a: Type, b: Type) {
if (a.length >= b.length) {
return a;
} else {
return b;
}
}
 
// longerArray is of type 'number[]'
const longerArray = longest([1, 2], [1, 2, 3]);
// longerString is of type 'alice' | 'bob'
const longerString = longest("alice", "bob");
// Error! Numbers don't have a 'length' property
const notOK = longest(10, 100);
Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.2345Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
Try

この例には、いくつかの興味深い点があります。TypeScriptに`longest`の戻り値型を推論させました。戻り値型の推論は、ジェネリック関数でも機能します。

`Type`を`{ length: number }`に制約したため、`a`と`b`パラメーターの`length`プロパティにアクセスできました。型制約がない場合、値がlengthプロパティを持たない他の型である可能性があるため、これらのプロパティにアクセスすることはできません。

`longerArray`と`longerString`の型は、引数に基づいて推論されました。ジェネリックは、すべて同じ型の2つ以上の値を関連付けることについてです!

最後に、期待通り、`longest(10, 100)`への呼び出しは拒否されます。なぜなら、`number`型には`length`プロパティがないからです。

制約付き値の扱い

ジェネリック制約を扱う際の一般的なエラーを以下に示します。

ts
function minimumLength<Type extends { length: number }>(
obj: Type,
minimum: number
): Type {
if (obj.length >= minimum) {
return obj;
} else {
return { length: minimum };
Type '{ length: number; }' is not assignable to type 'Type'. '{ length: number; }' is assignable to the constraint of type 'Type', but 'Type' could be instantiated with a different subtype of constraint '{ length: number; }'.2322Type '{ length: number; }' is not assignable to type 'Type'. '{ length: number; }' is assignable to the constraint of type 'Type', but 'Type' could be instantiated with a different subtype of constraint '{ length: number; }'.
}
}
Try

この関数は問題ないように見えるかもしれません。`Type`は`{ length: number }`に制約されており、関数は`Type`またはその制約に一致する値を返します。問題は、関数が制約に一致するオブジェクトではなく、渡されたものと*同じ*種類のオブジェクトを返すことを約束していることです。このコードが合法であれば、確実に動作しないコードを書くことができます。

ts
// 'arr' gets value { length: 6 }
const arr = minimumLength([1, 2, 3], 6);
// and crashes here because arrays have
// a 'slice' method, but not the returned object!
console.log(arr.slice(0));
Try

型引数の指定

TypeScriptは通常、ジェネリック呼び出しで意図された型引数を推論できますが、必ずしもそうではありません。たとえば、2つの配列を結合する関数を記述したとします。

ts
function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
return arr1.concat(arr2);
}
Try

通常、一致しない配列でこの関数を呼び出すことはエラーになります。

ts
const arr = combine([1, 2, 3], ["hello"]);
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
Try

ただし、このようにしたい場合は、`Type`を手動で指定できます。

ts
const arr = combine<string | number>([1, 2, 3], ["hello"]);
Try

優れたジェネリック関数を記述するためのガイドライン

ジェネリック関数の記述は楽しく、型パラメーターに夢中になりがちです。型パラメーターが多すぎるか、必要のない場所で制約を使用すると、推論の成功率が低下し、関数の呼び出し元をイライラさせる可能性があります。

型パラメーターを下に移動する

一見似ている関数を記述する2つの方法を以下に示します。

ts
function firstElement1<Type>(arr: Type[]) {
return arr[0];
}
 
function firstElement2<Type extends any[]>(arr: Type) {
return arr[0];
}
 
// a: number (good)
const a = firstElement1([1, 2, 3]);
// b: any (bad)
const b = firstElement2([1, 2, 3]);
Try

一見同じように見えるかもしれませんが、`firstElement1`はこの関数を記述するはるかに優れた方法です。その推論された戻り値型は`Type`ですが、`firstElement2`の推論された戻り値型は`any`です。なぜなら、TypeScriptは制約型を使用して`arr[0]`式を解決する必要があるためです。「呼び出し中に」要素の解決を「待つ」のではなく。

**ルール**: 可能な場合は、制約するのではなく、型パラメーター自体を使用します。

型パラメーターを減らす

ここでは、別のペアの類似した関数を示します。

ts
function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
return arr.filter(func);
}
 
function filter2<Type, Func extends (arg: Type) => boolean>(
arr: Type[],
func: Func
): Type[] {
return arr.filter(func);
}
Try

2つの値を関連付けない`Func`という型パラメーターを作成しました。これは常に危険信号です。なぜなら、型引数を指定したい呼び出し元は、理由もなく余分な型引数を手動で指定する必要があるからです。`Func`は、関数の可読性と推論性を低下させるだけです!

**ルール**: 常に可能な限り少ない型パラメーターを使用します。

型パラメーターは2回出現する必要があります

関数がジェネリックである必要がないことを忘れてしまうことがあります。

ts
function greet<Str extends string>(s: Str) {
console.log("Hello, " + s);
}
 
greet("world");
Try

より単純なバージョンを書くこともできました。

ts
function greet(s: string) {
console.log("Hello, " + s);
}
Try

覚えておいてください。型パラメーターは、複数の値の型を関連付けるためのものです。型パラメーターが関数シグネチャに1回しか使用されていない場合、何も関連付けられていません。これには推論された戻り値型も含まれます。たとえば、`Str`が`greet`の推論された戻り値型の一部であった場合、引数と戻り値の型を関連付けるため、記述されたコードには1回しか表示されなくても、2回使用されます。

**ルール**: 型パラメーターが1つの場所のみに表示される場合は、実際に必要かどうかを慎重に検討してください。

オプションのパラメーター

JavaScriptの関数は、多くの場合、可変数の引数を取ります。たとえば、`number`の`toFixed`メソッドは、オプションの桁数を取得します。

ts
function f(n: number) {
console.log(n.toFixed()); // 0 arguments
console.log(n.toFixed(3)); // 1 argument
}
Try

`?`を使用してパラメーターをオプションとしてマークすることで、TypeScriptでこれをモデル化できます。

ts
function f(x?: number) {
// ...
}
f(); // OK
f(10); // OK
Try

パラメーターは`number`型として指定されていますが、`x`パラメーターの型は実際には`number | undefined`になります。なぜなら、JavaScriptで指定されていないパラメーターは`undefined`という値になるからです。

パラメーターのデフォルト値も提供できます。

ts
function f(x = 10) {
// ...
}
Try

これで、`f`の本体では、`undefined`の引数は`10`で置き換えられるため、`x`の型は`number`になります。パラメーターがオプションの場合、呼び出し元は常に`undefined`を渡すことができます。これは単に「欠落した」引数をシミュレートします。

ts
// All OK
f();
f(10);
f(undefined);
Try

コールバックにおけるオプションのパラメーター

オプションのパラメーターと関数型式について学習したら、コールバックを呼び出す関数を記述するときに、次の間違いを犯しやすいです。

ts
function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
for (let i = 0; i < arr.length; i++) {
callback(arr[i], i);
}
}
Try

人が`index?`をオプションのパラメーターとして記述するときに通常意図しているのは、次の両方の呼び出しを合法的にしたいということです。

ts
myForEach([1, 2, 3], (a) => console.log(a));
myForEach([1, 2, 3], (a, i) => console.log(a, i));
Try

これが実際の意味するのは、`callback`が1つの引数で呼び出される可能性があるということです。言い換えれば、関数の定義は、実装が次のようになる可能性があることを示しています。

ts
function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
for (let i = 0; i < arr.length; i++) {
// I don't feel like providing the index today
callback(arr[i]);
}
}
Try

結果として、TypeScriptはこの意味を強制し、実際には起こりえないエラーを発行します。

ts
myForEach([1, 2, 3], (a, i) => {
console.log(i.toFixed());
'i' is possibly 'undefined'.18048'i' is possibly 'undefined'.
});
Try

JavaScriptでは、パラメーターよりも多くの引数で関数を呼び出す場合、余分な引数は単に無視されます。TypeScriptも同じように動作します。(同じ型の)パラメーターの少ない関数は、常にパラメーターの多い関数の代わりに使用できます。

**ルール**: コールバックの関数型を記述する場合は、その引数を渡さずに関数を呼び出すつもりでない限り、オプションのパラメーターを*決して*記述しないでください。

関数のオーバーロード

いくつかのJavaScript関数は、さまざまな引数の数と型で呼び出すことができます。たとえば、タイムスタンプ(1つの引数)または月/日/年の指定(3つの引数)のいずれかを受け取る`Date`を生成する関数を作成する場合があります。

TypeScriptでは、*オーバーロードシグネチャ*を書くことで、異なる方法で呼び出すことができる関数を指定できます。これを行うには、いくつかの関数シグネチャ(通常は2つ以上)を書き、その後に関数の本体を書きます。

ts
function makeDate(timestamp: number): Date;
function makeDate(m: number, d: number, y: number): Date;
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3);
No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.2575No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.
Try

この例では、2つのオーバーロードを記述しました。1つは1つの引数を受け入れ、もう1つは3つの引数を受け入れます。最初の2つのシグネチャは*オーバーロードシグネチャ*と呼ばれます。

次に、互換性のあるシグネチャを持つ関数の実装を記述しました。関数は*実装*シグネチャを持ちますが、このシグネチャは直接呼び出すことはできません。必須の引数の後に2つのオプションのパラメータを持つ関数を記述しましたが、2つのパラメータで呼び出すことはできません!

オーバーロードシグネチャと実装シグネチャ

これはよくある混乱の原因です。しばしば、人々はこのようなコードを書き、なぜエラーが発生するのか理解できません。

ts
function fn(x: string): void;
function fn() {
// ...
}
// Expected to be able to call with zero arguments
fn();
Expected 1 arguments, but got 0.2554Expected 1 arguments, but got 0.
Try

繰り返しますが、関数本体を記述するために使用されるシグネチャは、外部からは「見ることができません」。

実装のシグネチャは外部からは見えません。オーバーロードされた関数を記述する際には、常に関数の本体の上に関数のシグネチャを*2つ以上*記述する必要があります。

実装シグネチャは、オーバーロードシグネチャとも*互換性*がある必要があります。たとえば、これらの関数は、実装シグネチャが正しい方法でオーバーロードと一致していないため、エラーが発生します。

ts
function fn(x: boolean): void;
// Argument type isn't right
function fn(x: string): void;
This overload signature is not compatible with its implementation signature.2394This overload signature is not compatible with its implementation signature.
function fn(x: boolean) {}
Try
ts
function fn(x: string): string;
// Return type isn't right
function fn(x: number): boolean;
This overload signature is not compatible with its implementation signature.2394This overload signature is not compatible with its implementation signature.
function fn(x: string | number) {
return "oops";
}
Try

良好なオーバーロードの記述

ジェネリクスと同様に、関数オーバーロードを使用する際には、いくつかのガイドラインに従う必要があります。これらの原則に従うことで、関数の呼び出し、理解、実装が容易になります。

文字列または配列の長さを返す関数を考えてみましょう。

ts
function len(s: string): number;
function len(arr: any[]): number;
function len(x: any) {
return x.length;
}
Try

この関数は問題ありません。文字列または配列で呼び出すことができます。ただし、文字列または配列である可能性のある値で呼び出すことはできません。TypeScriptは関数呼び出しを単一のオーバーロードにしか解決できないためです。

ts
len(""); // OK
len([0]); // OK
len(Math.random() > 0.5 ? "hello" : [0]);
No overload matches this call. Overload 1 of 2, '(s: string): number', gave the following error. Argument of type 'number[] | "hello"' is not assignable to parameter of type 'string'. Type 'number[]' is not assignable to type 'string'. Overload 2 of 2, '(arr: any[]): number', gave the following error. Argument of type 'number[] | "hello"' is not assignable to parameter of type 'any[]'. Type 'string' is not assignable to type 'any[]'.2769No overload matches this call. Overload 1 of 2, '(s: string): number', gave the following error. Argument of type 'number[] | "hello"' is not assignable to parameter of type 'string'. Type 'number[]' is not assignable to type 'string'. Overload 2 of 2, '(arr: any[]): number', gave the following error. Argument of type 'number[] | "hello"' is not assignable to parameter of type 'any[]'. Type 'string' is not assignable to type 'any[]'.
Try

両方のオーバーロードの引数の数と戻り値の型が同じであるため、代わりにオーバーロードされていないバージョンの関数を記述できます。

ts
function len(x: any[] | string) {
return x.length;
}
Try

これははるかに優れています!呼び出し元はどちらの種類の値でもこれを使用でき、さらに、正しい実装シグネチャを考え出す必要もありません。

可能な場合は、常にオーバーロードではなく、ユニオン型のパラメータを優先してください。

関数内で`this`を宣言する

TypeScriptは、コードフロー分析を通じて、関数内の`this`が何であるかを推論します。たとえば、次のようになります。

ts
const user = {
id: 123,
 
admin: false,
becomeAdmin: function () {
this.admin = true;
},
};
Try

TypeScriptは、関数`user.becomeAdmin`に対応する`this`があり、それが外部オブジェクト`user`であることを理解しています。`this`は、多くの場合で十分ですが、`this`が表すオブジェクトをより詳細に制御する必要がある場合も多くあります。JavaScriptの仕様では、`this`という名前のパラメータを持つことはできないとされており、TypeScriptはこの構文空間を使用して、関数本体内の`this`の型を宣言できるようにしています。

ts
interface DB {
filterUsers(filter: (this: User) => boolean): User[];
}
 
const db = getDB();
const admins = db.filterUsers(function (this: User) {
return this.admin;
});
Try

このパターンは、コールバックスタイルのAPIで一般的です。別のオブジェクトが通常、関数の呼び出しタイミングを制御します。この動作を得るには、アロー関数ではなく`function`を使用する必要があることに注意してください。

ts
interface DB {
filterUsers(filter: (this: User) => boolean): User[];
}
 
const db = getDB();
const admins = db.filterUsers(() => this.admin);
The containing arrow function captures the global value of 'this'.
Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
7041
7017
The containing arrow function captures the global value of 'this'.
Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
Try

その他の型について

関数型を使用する際に頻繁に表示される、認識しておく必要がある追加の型がいくつかあります。すべての型と同様に、どこでも使用できますが、これらは関数に特に関連しています。

void

voidは、値を返さない関数の戻り値を表します。`return`文がない場合、またはそれらの`return`文から明示的な値を返さない場合、常に推論される型です。

ts
// The inferred return type is void
function noop() {
return;
}
Try

JavaScriptでは、値を返さない関数は暗黙的に値`undefined`を返します。しかし、voidundefinedはTypeScriptでは同じものではありません。この章の最後にさらに詳細があります。

voidundefinedと同じではありません。

object

特別な型objectは、プリミティブ(stringnumberbigintbooleansymbolnull、またはundefined)ではないすべての値を参照します。これは、*空のオブジェクト型*{}とは異なり、グローバル型Objectとも異なります。Objectを使用することはほとんどないでしょう。

objectObjectではありません。**常に**objectを使用してください!

JavaScriptでは、関数値はオブジェクトであることに注意してください。プロパティを持ち、プロトタイプチェーンに`Object.prototype`を持ち、`instanceof Object`であり、`Object.keys`を呼び出すことができます。このため、関数型はTypeScriptではobjectと見なされます。

unknown

unknown型は、*任意の*値を表します。これはany型に似ていますが、unknown値では何も行うことができないため、より安全です。

ts
function f1(a: any) {
a.b(); // OK
}
function f2(a: unknown) {
a.b();
'a' is of type 'unknown'.18046'a' is of type 'unknown'.
}
Try

これは、関数型を記述する際に役立ちます。関数本体にany値を含めることなく、任意の値を受け入れる関数を記述できるためです。

逆に、不明な型の値を返す関数を記述できます。

ts
function safeParse(s: string): unknown {
return JSON.parse(s);
}
 
// Need to be careful with 'obj'!
const obj = safeParse(someRandomString);
Try

never

いくつかの関数は*決して*値を返しません。

ts
function fail(msg: string): never {
throw new Error(msg);
}
Try

never型は、*決して*観測されない値を表します。戻り値の型では、これは関数が例外をスローするか、プログラムの実行を終了することを意味します。

neverは、TypeScriptがユニオンに残りの何もないことを判断した場合にも表示されます。

ts
function fn(x: string | number) {
if (typeof x === "string") {
// do something
} else if (typeof x === "number") {
// do something else
} else {
x; // has type 'never'!
}
}
Try

Function

グローバル型Functionは、JavaScriptのすべての関数値に存在する`bind`、`call`、`apply`などのプロパティを記述しています。また、Function型の値は常に呼び出すことができるという特殊なプロパティも持っています。これらの呼び出しはanyを返します。

ts
function doSomething(f: Function) {
return f(1, 2, 3);
}
Try

これは*型指定されていない関数呼び出し*であり、安全ではないany戻り値の型のため、一般的に避けるべきです。

任意の関数を許可する必要があるが、呼び出すつもりがない場合は、型`() => void`の方が一般的に安全です。

Restパラメータと引数

背景となる情報
Restパラメータ
スプレッド構文

Restパラメータ

オプションのパラメータやオーバーロードを使用して、さまざまな固定された引数の数を許容する関数を作成することに加えて、*Restパラメータ*を使用して、*無制限の*数の引数を受け取る関数を定義することもできます。

Restパラメータは、他のすべてのパラメータの後に出現し、`...`構文を使用します。

ts
function multiply(n: number, ...m: number[]) {
return m.map((x) => n * x);
}
// 'a' gets value [10, 20, 30, 40]
const a = multiply(10, 1, 2, 3, 4);
Try

TypeScriptでは、これらのパラメーターの型アノテーションは、anyではなく暗黙的にany[]となり、指定された型アノテーションはArray<T>またはT[]、あるいはタプル型(後述)でなければなりません。

Restパラメーター

逆に、スプレッド構文を使用して、反復可能なオブジェクト(例えば、配列)から可変数の引数を提供できます。例えば、配列のpushメソッドは任意の数の引数を取ります。

ts
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
arr1.push(...arr2);
Try

一般的に、TypeScriptは配列が不変であると仮定しません。これは、予期せぬ動作につながる可能性があります。

ts
// Inferred type is number[] -- "an array with zero or more numbers",
// not specifically two numbers
const args = [8, 5];
const angle = Math.atan2(...args);
A spread argument must either have a tuple type or be passed to a rest parameter.2556A spread argument must either have a tuple type or be passed to a rest parameter.
Try

この状況に対する最良の解決策はコードによって多少異なりますが、一般的にはconstコンテキストが最も簡単な解決策です。

ts
// Inferred as 2-length tuple
const args = [8, 5] as const;
// OK
const angle = Math.atan2(...args);
Try

Restパラメーターを使用するには、古いランタイムをターゲットにしている場合、downlevelIterationを有効にする必要がある場合があります。

パラメーターのデストラクチャリング

背景となる情報
デストラクチャリング代入

パラメーターのデストラクチャリングを使用して、引数として渡されたオブジェクトを、関数の本体内の1つ以上のローカル変数に簡単に展開できます。JavaScriptでは、次のようになります。

js
function sum({ a, b, c }) {
console.log(a + b + c);
}
sum({ a: 10, b: 3, c: 9 });

オブジェクトの型アノテーションは、デストラクチャリング構文の後に記述します。

ts
function sum({ a, b, c }: { a: number; b: number; c: number }) {
console.log(a + b + c);
}
Try

これは少し冗長に見えるかもしれませんが、ここで名前付き型を使用することもできます。

ts
// Same as prior example
type ABC = { a: number; b: number; c: number };
function sum({ a, b, c }: ABC) {
console.log(a + b + c);
}
Try

関数の代入可能性

戻り値の型void

関数のvoid戻り値の型は、いくつかの珍しいが予想される動作を生み出す可能性があります。

voidの戻り値の型を持つコンテキスト型は、関数が何かを返さないことを強制するものではありません。言い換えると、void戻り値の型を持つコンテキスト関数型(`type voidFunc = () => void`)は、実装時に他の任意の値を返すことができますが、それは無視されます。

したがって、() => void型の次の実装は有効です。

ts
type voidFunc = () => void;
 
const f1: voidFunc = () => {
return true;
};
 
const f2: voidFunc = () => true;
 
const f3: voidFunc = function () {
return true;
};
Try

そして、これらの関数の戻り値が別の変数に代入されると、voidの型を保持します。

ts
const v1 = f1();
 
const v2 = f2();
 
const v3 = f3();
Try

この動作が存在するのは、Array.prototype.pushは数値を返し、Array.prototype.forEachメソッドは戻り値の型がvoidの関数を期待しているにもかかわらず、次のコードが有効になるためです。

ts
const src = [1, 2, 3];
const dst = [0];
 
src.forEach((el) => dst.push(el));
Try

もう1つの特別なケースに注意が必要です。リテラル関数定義にvoid戻り値の型がある場合、その関数は何も返すことができません。

ts
function f2(): void {
// @ts-expect-error
return true;
}
 
const f3 = function (): void {
// @ts-expect-error
return true;
};
Try

voidの詳細については、他のドキュメントを参照してください。

TypeScriptドキュメントはオープンソースプロジェクトです。Pull Requestを送信して、これらのページの改善にご協力ください by sending a Pull Request

このページへの貢献者
RCRyan Cavanaugh (56)
OTOrta Therox (15)
HAHossein Ahmadian-Yazdi (4)
JWJoseph Wynn (3)
SBSiarhei Bobryk (2)
34+

最終更新日:2024年3月21日