関数は、ローカル関数、別のモジュールからインポートされた関数、またはクラスのメソッドなど、あらゆるアプリケーションの基本的な構成要素です。それらは値でもあるため、他の値と同様に、TypeScript には関数の呼び出し方法を記述する多くの方法があります。関数を記述する型を記述する方法を学びましょう。
関数型式
関数を記述する最も簡単な方法は、関数型式を使用することです。これらの型は構文的にアロー関数に似ています。
tsTryfunctiongreeter (fn : (a : string) => void) {fn ("Hello, World");}functionprintToConsole (s : string) {console .log (s );}greeter (printToConsole );
構文 (a: string) => void は、「`a` という名前の 1 つの引数を持つ関数で、型は `string` であり、戻り値がない」という意味です。関数宣言と同様に、引数の型が指定されていない場合、暗黙的に `any` となります。
引数名は**必須**であることに注意してください。関数型 `(string) => void` は、「`string` という名前の引数(型は `any`)を持つ関数」という意味です!
もちろん、型エイリアスを使用して関数型に名前を付けることができます。
tsTrytypeGreetFunction = (a : string) => void;functiongreeter (fn :GreetFunction ) {// ...}
呼び出しシグネチャ
JavaScript では、関数は呼び出し可能であることに加えて、プロパティを持つことができます。ただし、関数型式構文ではプロパティの宣言はできません。プロパティを持つ呼び出し可能なものを記述する場合は、オブジェクト型に呼び出しシグネチャを記述できます。
tsTrytypeDescribableFunction = {description : string;(someArg : number): boolean;};functiondoSomething (fn :DescribableFunction ) {console .log (fn .description + " returned " +fn (6));}functionmyFunc (someArg : number) {returnsomeArg > 3;}myFunc .description = "default description";doSomething (myFunc );
関数型式と比べて構文がわずかに異なることに注意してください。引数リストと戻り値の型の間には `=>` ではなく `:` を使用します。
コンストラクトシグネチャ
JavaScript 関数は、`new` 演算子を使用して呼び出すこともできます。TypeScript は、通常新しいオブジェクトを作成するため、これらをコンストラクターと呼びます。`new`キーワードを呼び出しシグネチャの前に追加することで、コンストラクトシグネチャを記述できます。
tsTrytypeSomeConstructor = {new (s : string):SomeObject ;};functionfn (ctor :SomeConstructor ) {return newctor ("hello");}
JavaScript の `Date` オブジェクトなどの一部のオブジェクトは、`new` を使用してまたは使用せずに呼び出すことができます。呼び出しシグネチャとコンストラクトシグネチャは、同じ型に任意に組み合わせることができます。
tsTryinterfaceCallOrConstruct {(n ?: number): string;new (s : string):Date ;}
ジェネリック関数
入力の型が出力の型に関連付けられている関数、または2つの入力の型が何らかの方法で関連付けられている関数を記述することは一般的です。配列の最初の要素を返す関数を考えてみましょう。
tsTryfunctionfirstElement (arr : any[]) {returnarr [0];}
この関数はその役割を果たしますが、残念ながら戻り値の型は `any` です。関数が配列要素の型を返す方が良いでしょう。
TypeScript では、2つの値間の対応関係を記述する必要がある場合にジェネリクスが使用されます。これは、関数シグネチャに型パラメーターを宣言することで行います。
tsTryfunctionfirstElement <Type >(arr :Type []):Type | undefined {returnarr [0];}
この関数に型パラメーター `Type` を追加し、2つの場所でそれを使用することで、関数の入力(配列)と出力(戻り値)の間にリンクを作成しました。これで、呼び出すとより具体的な型が出力されます。
tsTry// s is of type 'string'consts =firstElement (["a", "b", "c"]);// n is of type 'number'constn =firstElement ([1, 2, 3]);// u is of type undefinedconstu =firstElement ([]);
推論
このサンプルでは `Type` を指定する必要がなかったことに注意してください。型は TypeScript によって推論されました(自動的に選択されました)。
複数型パラメーターも使用できます。たとえば、`map` のスタンドアロンバージョンは次のようになります。
tsTryfunctionmap <Input ,Output >(arr :Input [],func : (arg :Input ) =>Output ):Output [] {returnarr .map (func );}// Parameter 'n' is of type 'string'// 'parsed' is of type 'number[]'constparsed =map (["1", "2", "3"], (n ) =>parseInt (n ));
この例では、TypeScript は `Input` 型パラメーターの型(指定された `string` 配列から)と `Output` 型パラメーターの型(関数式の戻り値 `number` から)の両方を推論できます。
制約事項
あらゆる種類の値で動作する汎用的な関数をいくつか記述しました。2つの値を関連付ける必要がある場合がありますが、特定の値のサブセットでのみ操作できます。この場合、制約を使用して、型パラメーターが受け入れることができる型の種類を制限できます。
2つの値のうち、より長い方を返す関数を作成しましょう。そのためには、数値である`length`プロパティが必要です。`extends`句を記述することで、型パラメーターをその型に制約します。
tsTryfunctionlongest <Type extends {length : number }>(a :Type ,b :Type ) {if (a .length >=b .length ) {returna ;} else {returnb ;}}// longerArray is of type 'number[]'constlongerArray =longest ([1, 2], [1, 2, 3]);// longerString is of type 'alice' | 'bob'constlongerString =longest ("alice", "bob");// Error! Numbers don't have a 'length' propertyconstArgument 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; }'.notOK =longest (10 , 100);
この例には、いくつかの興味深い点があります。TypeScriptに`longest`の戻り値型を推論させました。戻り値型の推論は、ジェネリック関数でも機能します。
`Type`を`{ length: number }`に制約したため、`a`と`b`パラメーターの`length`プロパティにアクセスできました。型制約がない場合、値がlengthプロパティを持たない他の型である可能性があるため、これらのプロパティにアクセスすることはできません。
`longerArray`と`longerString`の型は、引数に基づいて推論されました。ジェネリックは、すべて同じ型の2つ以上の値を関連付けることについてです!
最後に、期待通り、`longest(10, 100)`への呼び出しは拒否されます。なぜなら、`number`型には`length`プロパティがないからです。
制約付き値の扱い
ジェネリック制約を扱う際の一般的なエラーを以下に示します。
tsTryfunctionminimumLength <Type extends {length : number }>(obj :Type ,minimum : number):Type {if (obj .length >=minimum ) {returnobj ;} else {return {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; }'.length :minimum };}}
この関数は問題ないように見えるかもしれません。`Type`は`{ length: number }`に制約されており、関数は`Type`またはその制約に一致する値を返します。問題は、関数が制約に一致するオブジェクトではなく、渡されたものと*同じ*種類のオブジェクトを返すことを約束していることです。このコードが合法であれば、確実に動作しないコードを書くことができます。
tsTry// 'arr' gets value { length: 6 }constarr =minimumLength ([1, 2, 3], 6);// and crashes here because arrays have// a 'slice' method, but not the returned object!console .log (arr .slice (0));
型引数の指定
TypeScriptは通常、ジェネリック呼び出しで意図された型引数を推論できますが、必ずしもそうではありません。たとえば、2つの配列を結合する関数を記述したとします。
tsTryfunctioncombine <Type >(arr1 :Type [],arr2 :Type []):Type [] {returnarr1 .concat (arr2 );}
通常、一致しない配列でこの関数を呼び出すことはエラーになります。
tsTryconstType 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.arr =combine ([1, 2, 3], ["hello" ]);
ただし、このようにしたい場合は、`Type`を手動で指定できます。
tsTryconstarr =combine <string | number>([1, 2, 3], ["hello"]);
優れたジェネリック関数を記述するためのガイドライン
ジェネリック関数の記述は楽しく、型パラメーターに夢中になりがちです。型パラメーターが多すぎるか、必要のない場所で制約を使用すると、推論の成功率が低下し、関数の呼び出し元をイライラさせる可能性があります。
型パラメーターを下に移動する
一見似ている関数を記述する2つの方法を以下に示します。
tsTryfunctionfirstElement1 <Type >(arr :Type []) {returnarr [0];}functionfirstElement2 <Type extends any[]>(arr :Type ) {returnarr [0];}// a: number (good)consta =firstElement1 ([1, 2, 3]);// b: any (bad)constb =firstElement2 ([1, 2, 3]);
一見同じように見えるかもしれませんが、`firstElement1`はこの関数を記述するはるかに優れた方法です。その推論された戻り値型は`Type`ですが、`firstElement2`の推論された戻り値型は`any`です。なぜなら、TypeScriptは制約型を使用して`arr[0]`式を解決する必要があるためです。「呼び出し中に」要素の解決を「待つ」のではなく。
**ルール**: 可能な場合は、制約するのではなく、型パラメーター自体を使用します。
型パラメーターを減らす
ここでは、別のペアの類似した関数を示します。
tsTryfunctionfilter1 <Type >(arr :Type [],func : (arg :Type ) => boolean):Type [] {returnarr .filter (func );}functionfilter2 <Type ,Func extends (arg :Type ) => boolean>(arr :Type [],func :Func ):Type [] {returnarr .filter (func );}
2つの値を関連付けない`Func`という型パラメーターを作成しました。これは常に危険信号です。なぜなら、型引数を指定したい呼び出し元は、理由もなく余分な型引数を手動で指定する必要があるからです。`Func`は、関数の可読性と推論性を低下させるだけです!
**ルール**: 常に可能な限り少ない型パラメーターを使用します。
型パラメーターは2回出現する必要があります
関数がジェネリックである必要がないことを忘れてしまうことがあります。
tsTryfunctiongreet <Str extends string>(s :Str ) {console .log ("Hello, " +s );}greet ("world");
より単純なバージョンを書くこともできました。
tsTryfunctiongreet (s : string) {console .log ("Hello, " +s );}
覚えておいてください。型パラメーターは、複数の値の型を関連付けるためのものです。型パラメーターが関数シグネチャに1回しか使用されていない場合、何も関連付けられていません。これには推論された戻り値型も含まれます。たとえば、`Str`が`greet`の推論された戻り値型の一部であった場合、引数と戻り値の型を関連付けるため、記述されたコードには1回しか表示されなくても、2回使用されます。
**ルール**: 型パラメーターが1つの場所のみに表示される場合は、実際に必要かどうかを慎重に検討してください。
オプションのパラメーター
JavaScriptの関数は、多くの場合、可変数の引数を取ります。たとえば、`number`の`toFixed`メソッドは、オプションの桁数を取得します。
tsTryfunctionf (n : number) {console .log (n .toFixed ()); // 0 argumentsconsole .log (n .toFixed (3)); // 1 argument}
`?`を使用してパラメーターをオプションとしてマークすることで、TypeScriptでこれをモデル化できます。
tsTryfunctionf (x ?: number) {// ...}f (); // OKf (10); // OK
パラメーターは`number`型として指定されていますが、`x`パラメーターの型は実際には`number | undefined`になります。なぜなら、JavaScriptで指定されていないパラメーターは`undefined`という値になるからです。
パラメーターのデフォルト値も提供できます。
tsTryfunctionf (x = 10) {// ...}
これで、`f`の本体では、`undefined`の引数は`10`で置き換えられるため、`x`の型は`number`になります。パラメーターがオプションの場合、呼び出し元は常に`undefined`を渡すことができます。これは単に「欠落した」引数をシミュレートします。
tsTry// All OKf ();f (10);f (undefined );
コールバックにおけるオプションのパラメーター
オプションのパラメーターと関数型式について学習したら、コールバックを呼び出す関数を記述するときに、次の間違いを犯しやすいです。
tsTryfunctionmyForEach (arr : any[],callback : (arg : any,index ?: number) => void) {for (leti = 0;i <arr .length ;i ++) {callback (arr [i ],i );}}
人が`index?`をオプションのパラメーターとして記述するときに通常意図しているのは、次の両方の呼び出しを合法的にしたいということです。
tsTrymyForEach ([1, 2, 3], (a ) =>console .log (a ));myForEach ([1, 2, 3], (a ,i ) =>console .log (a ,i ));
これが実際の意味するのは、`callback`が1つの引数で呼び出される可能性があるということです。言い換えれば、関数の定義は、実装が次のようになる可能性があることを示しています。
tsTryfunctionmyForEach (arr : any[],callback : (arg : any,index ?: number) => void) {for (leti = 0;i <arr .length ;i ++) {// I don't feel like providing the index todaycallback (arr [i ]);}}
結果として、TypeScriptはこの意味を強制し、実際には起こりえないエラーを発行します。
tsTrymyForEach ([1, 2, 3], (a ,i ) => {'i' is possibly 'undefined'.18048'i' is possibly 'undefined'.console .log (. i toFixed ());});
JavaScriptでは、パラメーターよりも多くの引数で関数を呼び出す場合、余分な引数は単に無視されます。TypeScriptも同じように動作します。(同じ型の)パラメーターの少ない関数は、常にパラメーターの多い関数の代わりに使用できます。
**ルール**: コールバックの関数型を記述する場合は、その引数を渡さずに関数を呼び出すつもりでない限り、オプションのパラメーターを*決して*記述しないでください。
関数のオーバーロード
いくつかのJavaScript関数は、さまざまな引数の数と型で呼び出すことができます。たとえば、タイムスタンプ(1つの引数)または月/日/年の指定(3つの引数)のいずれかを受け取る`Date`を生成する関数を作成する場合があります。
TypeScriptでは、*オーバーロードシグネチャ*を書くことで、異なる方法で呼び出すことができる関数を指定できます。これを行うには、いくつかの関数シグネチャ(通常は2つ以上)を書き、その後に関数の本体を書きます。
tsTryfunctionmakeDate (timestamp : number):Date ;functionmakeDate (m : number,d : number,y : number):Date ;functionmakeDate (mOrTimestamp : number,d ?: number,y ?: number):Date {if (d !==undefined &&y !==undefined ) {return newDate (y ,mOrTimestamp ,d );} else {return newDate (mOrTimestamp );}}constd1 =makeDate (12345678);constd2 =makeDate (5, 5, 5);constNo 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.d3 =makeDate (1, 3);
この例では、2つのオーバーロードを記述しました。1つは1つの引数を受け入れ、もう1つは3つの引数を受け入れます。最初の2つのシグネチャは*オーバーロードシグネチャ*と呼ばれます。
次に、互換性のあるシグネチャを持つ関数の実装を記述しました。関数は*実装*シグネチャを持ちますが、このシグネチャは直接呼び出すことはできません。必須の引数の後に2つのオプションのパラメータを持つ関数を記述しましたが、2つのパラメータで呼び出すことはできません!
オーバーロードシグネチャと実装シグネチャ
これはよくある混乱の原因です。しばしば、人々はこのようなコードを書き、なぜエラーが発生するのか理解できません。
tsTryfunctionfn (x : string): void;functionfn () {// ...}// Expected to be able to call with zero argumentsExpected 1 arguments, but got 0.2554Expected 1 arguments, but got 0.fn ();
繰り返しますが、関数本体を記述するために使用されるシグネチャは、外部からは「見ることができません」。
実装のシグネチャは外部からは見えません。オーバーロードされた関数を記述する際には、常に関数の本体の上に関数のシグネチャを*2つ以上*記述する必要があります。
実装シグネチャは、オーバーロードシグネチャとも*互換性*がある必要があります。たとえば、これらの関数は、実装シグネチャが正しい方法でオーバーロードと一致していないため、エラーが発生します。
tsTryfunctionfn (x : boolean): void;// Argument type isn't rightfunctionThis overload signature is not compatible with its implementation signature.2394This overload signature is not compatible with its implementation signature.( fn x : string): void;functionfn (x : boolean) {}
tsTryfunctionfn (x : string): string;// Return type isn't rightfunctionThis overload signature is not compatible with its implementation signature.2394This overload signature is not compatible with its implementation signature.( fn x : number): boolean;functionfn (x : string | number) {return "oops";}
良好なオーバーロードの記述
ジェネリクスと同様に、関数オーバーロードを使用する際には、いくつかのガイドラインに従う必要があります。これらの原則に従うことで、関数の呼び出し、理解、実装が容易になります。
文字列または配列の長さを返す関数を考えてみましょう。
tsTryfunctionlen (s : string): number;functionlen (arr : any[]): number;functionlen (x : any) {returnx .length ;}
この関数は問題ありません。文字列または配列で呼び出すことができます。ただし、文字列または配列である可能性のある値で呼び出すことはできません。TypeScriptは関数呼び出しを単一のオーバーロードにしか解決できないためです。
tsTrylen (""); // OKlen ([0]); // OKNo 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[]'.len (Math .random () > 0.5 ? "hello" : [0]);
両方のオーバーロードの引数の数と戻り値の型が同じであるため、代わりにオーバーロードされていないバージョンの関数を記述できます。
tsTryfunctionlen (x : any[] | string) {returnx .length ;}
これははるかに優れています!呼び出し元はどちらの種類の値でもこれを使用でき、さらに、正しい実装シグネチャを考え出す必要もありません。
可能な場合は、常にオーバーロードではなく、ユニオン型のパラメータを優先してください。
関数内で`this`を宣言する
TypeScriptは、コードフロー分析を通じて、関数内の`this`が何であるかを推論します。たとえば、次のようになります。
tsTryconstuser = {id : 123,admin : false,becomeAdmin : function () {this.admin = true;},};
TypeScriptは、関数`user.becomeAdmin`に対応する`this`があり、それが外部オブジェクト`user`であることを理解しています。`this`は、多くの場合で十分ですが、`this`が表すオブジェクトをより詳細に制御する必要がある場合も多くあります。JavaScriptの仕様では、`this`という名前のパラメータを持つことはできないとされており、TypeScriptはこの構文空間を使用して、関数本体内の`this`の型を宣言できるようにしています。
tsTryinterfaceDB {filterUsers (filter : (this :User ) => boolean):User [];}constdb =getDB ();constadmins =db .filterUsers (function (this :User ) {return this.admin ;});
このパターンは、コールバックスタイルのAPIで一般的です。別のオブジェクトが通常、関数の呼び出しタイミングを制御します。この動作を得るには、アロー関数ではなく`function`を使用する必要があることに注意してください。
tsTryinterfaceDB {filterUsers (filter : (this :User ) => boolean):User [];}constdb =getDB ();constThe containing arrow function captures the global value of 'this'.admins =db .filterUsers (() =>this .); admin
Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.7041
7017The containing arrow function captures the global value of 'this'.
Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
その他の型について
関数型を使用する際に頻繁に表示される、認識しておく必要がある追加の型がいくつかあります。すべての型と同様に、どこでも使用できますが、これらは関数に特に関連しています。
void
voidは、値を返さない関数の戻り値を表します。`return`文がない場合、またはそれらの`return`文から明示的な値を返さない場合、常に推論される型です。
tsTry// The inferred return type is voidfunctionnoop () {return;}
JavaScriptでは、値を返さない関数は暗黙的に値`undefined`を返します。しかし、voidとundefinedはTypeScriptでは同じものではありません。この章の最後にさらに詳細があります。
voidはundefinedと同じではありません。
object
特別な型objectは、プリミティブ(string、number、bigint、boolean、symbol、null、またはundefined)ではないすべての値を参照します。これは、*空のオブジェクト型*{}とは異なり、グローバル型Objectとも異なります。Objectを使用することはほとんどないでしょう。
objectはObjectではありません。**常に**objectを使用してください!
JavaScriptでは、関数値はオブジェクトであることに注意してください。プロパティを持ち、プロトタイプチェーンに`Object.prototype`を持ち、`instanceof Object`であり、`Object.keys`を呼び出すことができます。このため、関数型はTypeScriptではobjectと見なされます。
unknown
unknown型は、*任意の*値を表します。これはany型に似ていますが、unknown値では何も行うことができないため、より安全です。
tsTryfunctionf1 (a : any) {a .b (); // OK}functionf2 (a : unknown) {'a' is of type 'unknown'.18046'a' is of type 'unknown'.. a b ();}
これは、関数型を記述する際に役立ちます。関数本体にany値を含めることなく、任意の値を受け入れる関数を記述できるためです。
逆に、不明な型の値を返す関数を記述できます。
tsTryfunctionsafeParse (s : string): unknown {returnJSON .parse (s );}// Need to be careful with 'obj'!constobj =safeParse (someRandomString );
never
いくつかの関数は*決して*値を返しません。
tsTryfunctionfail (msg : string): never {throw newError (msg );}
never型は、*決して*観測されない値を表します。戻り値の型では、これは関数が例外をスローするか、プログラムの実行を終了することを意味します。
neverは、TypeScriptがユニオンに残りの何もないことを判断した場合にも表示されます。
tsTryfunctionfn (x : string | number) {if (typeofx === "string") {// do something} else if (typeofx === "number") {// do something else} else {x ; // has type 'never'!}}
Function
グローバル型Functionは、JavaScriptのすべての関数値に存在する`bind`、`call`、`apply`などのプロパティを記述しています。また、Function型の値は常に呼び出すことができるという特殊なプロパティも持っています。これらの呼び出しはanyを返します。
tsTryfunctiondoSomething (f :Function ) {returnf (1, 2, 3);}
これは*型指定されていない関数呼び出し*であり、安全ではないany戻り値の型のため、一般的に避けるべきです。
任意の関数を許可する必要があるが、呼び出すつもりがない場合は、型`() => void`の方が一般的に安全です。
Restパラメータと引数
Restパラメータ
オプションのパラメータやオーバーロードを使用して、さまざまな固定された引数の数を許容する関数を作成することに加えて、*Restパラメータ*を使用して、*無制限の*数の引数を受け取る関数を定義することもできます。
Restパラメータは、他のすべてのパラメータの後に出現し、`...`構文を使用します。
tsTryfunctionmultiply (n : number, ...m : number[]) {returnm .map ((x ) =>n *x );}// 'a' gets value [10, 20, 30, 40]consta =multiply (10, 1, 2, 3, 4);
TypeScriptでは、これらのパラメーターの型アノテーションは、anyではなく暗黙的にany[]となり、指定された型アノテーションはArray<T>またはT[]、あるいはタプル型(後述)でなければなりません。
Restパラメーター
逆に、スプレッド構文を使用して、反復可能なオブジェクト(例えば、配列)から可変数の引数を提供できます。例えば、配列のpushメソッドは任意の数の引数を取ります。
tsTryconstarr1 = [1, 2, 3];constarr2 = [4, 5, 6];arr1 .push (...arr2 );
一般的に、TypeScriptは配列が不変であると仮定しません。これは、予期せぬ動作につながる可能性があります。
tsTry// Inferred type is number[] -- "an array with zero or more numbers",// not specifically two numbersconstargs = [8, 5];constA 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.angle =Math .atan2 (...args );
この状況に対する最良の解決策はコードによって多少異なりますが、一般的にはconstコンテキストが最も簡単な解決策です。
tsTry// Inferred as 2-length tupleconstargs = [8, 5] asconst ;// OKconstangle =Math .atan2 (...args );
Restパラメーターを使用するには、古いランタイムをターゲットにしている場合、downlevelIterationを有効にする必要がある場合があります。
パラメーターのデストラクチャリング
背景となる情報
デストラクチャリング代入
パラメーターのデストラクチャリングを使用して、引数として渡されたオブジェクトを、関数の本体内の1つ以上のローカル変数に簡単に展開できます。JavaScriptでは、次のようになります。
jsfunction sum({ a, b, c }) {console.log(a + b + c);}sum({ a: 10, b: 3, c: 9 });
オブジェクトの型アノテーションは、デストラクチャリング構文の後に記述します。
tsTryfunctionsum ({a ,b ,c }: {a : number;b : number;c : number }) {console .log (a +b +c );}
これは少し冗長に見えるかもしれませんが、ここで名前付き型を使用することもできます。
tsTry// Same as prior exampletypeABC = {a : number;b : number;c : number };functionsum ({a ,b ,c }:ABC ) {console .log (a +b +c );}
関数の代入可能性
戻り値の型void
関数のvoid戻り値の型は、いくつかの珍しいが予想される動作を生み出す可能性があります。
voidの戻り値の型を持つコンテキスト型は、関数が何かを返さないことを強制するものではありません。言い換えると、void戻り値の型を持つコンテキスト関数型(`type voidFunc = () => void`)は、実装時に他の任意の値を返すことができますが、それは無視されます。
したがって、() => void型の次の実装は有効です。
tsTrytypevoidFunc = () => void;constf1 :voidFunc = () => {return true;};constf2 :voidFunc = () => true;constf3 :voidFunc = function () {return true;};
そして、これらの関数の戻り値が別の変数に代入されると、voidの型を保持します。
tsTryconstv1 =f1 ();constv2 =f2 ();constv3 =f3 ();
この動作が存在するのは、Array.prototype.pushは数値を返し、Array.prototype.forEachメソッドは戻り値の型がvoidの関数を期待しているにもかかわらず、次のコードが有効になるためです。
tsTryconstsrc = [1, 2, 3];constdst = [0];src .forEach ((el ) =>dst .push (el ));
もう1つの特別なケースに注意が必要です。リテラル関数定義にvoid戻り値の型がある場合、その関数は何も返すことができません。
tsTryfunctionf2 (): void {// @ts-expect-errorreturn true;}constf3 = function (): void {// @ts-expect-errorreturn true;};
voidの詳細については、他のドキュメントを参照してください。