関数は、ローカル関数、別のモジュールからインポートされた関数、またはクラスのメソッドなど、あらゆるアプリケーションの基本的な構成要素です。それらは値でもあるため、他の値と同様に、TypeScript には関数の呼び出し方法を記述する多くの方法があります。関数を記述する型を記述する方法を学びましょう。
関数型式
関数を記述する最も簡単な方法は、関数型式を使用することです。これらの型は構文的にアロー関数に似ています。
tsTry
functiongreeter (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`)を持つ関数」という意味です!
もちろん、型エイリアスを使用して関数型に名前を付けることができます。
tsTry
typeGreetFunction = (a : string) => void;functiongreeter (fn :GreetFunction ) {// ...}
呼び出しシグネチャ
JavaScript では、関数は呼び出し可能であることに加えて、プロパティを持つことができます。ただし、関数型式構文ではプロパティの宣言はできません。プロパティを持つ呼び出し可能なものを記述する場合は、オブジェクト型に呼び出しシグネチャを記述できます。
tsTry
typeDescribableFunction = {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`キーワードを呼び出しシグネチャの前に追加することで、コンストラクトシグネチャを記述できます。
tsTry
typeSomeConstructor = {new (s : string):SomeObject ;};functionfn (ctor :SomeConstructor ) {return newctor ("hello");}
JavaScript の `Date` オブジェクトなどの一部のオブジェクトは、`new` を使用してまたは使用せずに呼び出すことができます。呼び出しシグネチャとコンストラクトシグネチャは、同じ型に任意に組み合わせることができます。
tsTry
interfaceCallOrConstruct {(n ?: number): string;new (s : string):Date ;}
ジェネリック関数
入力の型が出力の型に関連付けられている関数、または2つの入力の型が何らかの方法で関連付けられている関数を記述することは一般的です。配列の最初の要素を返す関数を考えてみましょう。
tsTry
functionfirstElement (arr : any[]) {returnarr [0];}
この関数はその役割を果たしますが、残念ながら戻り値の型は `any` です。関数が配列要素の型を返す方が良いでしょう。
TypeScript では、2つの値間の対応関係を記述する必要がある場合にジェネリクスが使用されます。これは、関数シグネチャに型パラメーターを宣言することで行います。
tsTry
functionfirstElement <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` のスタンドアロンバージョンは次のようになります。
tsTry
functionmap <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`句を記述することで、型パラメーターをその型に制約します。
tsTry
functionlongest <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`プロパティがないからです。
制約付き値の扱い
ジェネリック制約を扱う際の一般的なエラーを以下に示します。
tsTry
functionminimumLength <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つの配列を結合する関数を記述したとします。
tsTry
functioncombine <Type >(arr1 :Type [],arr2 :Type []):Type [] {returnarr1 .concat (arr2 );}
通常、一致しない配列でこの関数を呼び出すことはエラーになります。
tsTry
constType 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.arr =combine ([1, 2, 3], ["hello" ]);
ただし、このようにしたい場合は、`Type`を手動で指定できます。
tsTry
constarr =combine <string | number>([1, 2, 3], ["hello"]);
優れたジェネリック関数を記述するためのガイドライン
ジェネリック関数の記述は楽しく、型パラメーターに夢中になりがちです。型パラメーターが多すぎるか、必要のない場所で制約を使用すると、推論の成功率が低下し、関数の呼び出し元をイライラさせる可能性があります。
型パラメーターを下に移動する
一見似ている関数を記述する2つの方法を以下に示します。
tsTry
functionfirstElement1 <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]`式を解決する必要があるためです。「呼び出し中に」要素の解決を「待つ」のではなく。
**ルール**: 可能な場合は、制約するのではなく、型パラメーター自体を使用します。
型パラメーターを減らす
ここでは、別のペアの類似した関数を示します。
tsTry
functionfilter1 <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回出現する必要があります
関数がジェネリックである必要がないことを忘れてしまうことがあります。
tsTry
functiongreet <Str extends string>(s :Str ) {console .log ("Hello, " +s );}greet ("world");
より単純なバージョンを書くこともできました。
tsTry
functiongreet (s : string) {console .log ("Hello, " +s );}
覚えておいてください。型パラメーターは、複数の値の型を関連付けるためのものです。型パラメーターが関数シグネチャに1回しか使用されていない場合、何も関連付けられていません。これには推論された戻り値型も含まれます。たとえば、`Str`が`greet`の推論された戻り値型の一部であった場合、引数と戻り値の型を関連付けるため、記述されたコードには1回しか表示されなくても、2回使用されます。
**ルール**: 型パラメーターが1つの場所のみに表示される場合は、実際に必要かどうかを慎重に検討してください。
オプションのパラメーター
JavaScriptの関数は、多くの場合、可変数の引数を取ります。たとえば、`number`の`toFixed`メソッドは、オプションの桁数を取得します。
tsTry
functionf (n : number) {console .log (n .toFixed ()); // 0 argumentsconsole .log (n .toFixed (3)); // 1 argument}
`?`を使用してパラメーターをオプションとしてマークすることで、TypeScriptでこれをモデル化できます。
tsTry
functionf (x ?: number) {// ...}f (); // OKf (10); // OK
パラメーターは`number`型として指定されていますが、`x`パラメーターの型は実際には`number | undefined`になります。なぜなら、JavaScriptで指定されていないパラメーターは`undefined`という値になるからです。
パラメーターのデフォルト値も提供できます。
tsTry
functionf (x = 10) {// ...}
これで、`f`の本体では、`undefined`の引数は`10`で置き換えられるため、`x`の型は`number`になります。パラメーターがオプションの場合、呼び出し元は常に`undefined`を渡すことができます。これは単に「欠落した」引数をシミュレートします。
tsTry
// All OKf ();f (10);f (undefined );
コールバックにおけるオプションのパラメーター
オプションのパラメーターと関数型式について学習したら、コールバックを呼び出す関数を記述するときに、次の間違いを犯しやすいです。
tsTry
functionmyForEach (arr : any[],callback : (arg : any,index ?: number) => void) {for (leti = 0;i <arr .length ;i ++) {callback (arr [i ],i );}}
人が`index?`をオプションのパラメーターとして記述するときに通常意図しているのは、次の両方の呼び出しを合法的にしたいということです。
tsTry
myForEach ([1, 2, 3], (a ) =>console .log (a ));myForEach ([1, 2, 3], (a ,i ) =>console .log (a ,i ));
これが実際の意味するのは、`callback`が1つの引数で呼び出される可能性があるということです。言い換えれば、関数の定義は、実装が次のようになる可能性があることを示しています。
tsTry
functionmyForEach (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はこの意味を強制し、実際には起こりえないエラーを発行します。
tsTry
myForEach ([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つ以上)を書き、その後に関数の本体を書きます。
tsTry
functionmakeDate (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つのパラメータで呼び出すことはできません!
オーバーロードシグネチャと実装シグネチャ
これはよくある混乱の原因です。しばしば、人々はこのようなコードを書き、なぜエラーが発生するのか理解できません。
tsTry
functionfn (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つ以上*記述する必要があります。
実装シグネチャは、オーバーロードシグネチャとも*互換性*がある必要があります。たとえば、これらの関数は、実装シグネチャが正しい方法でオーバーロードと一致していないため、エラーが発生します。
tsTry
functionfn (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) {}
tsTry
functionfn (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";}
良好なオーバーロードの記述
ジェネリクスと同様に、関数オーバーロードを使用する際には、いくつかのガイドラインに従う必要があります。これらの原則に従うことで、関数の呼び出し、理解、実装が容易になります。
文字列または配列の長さを返す関数を考えてみましょう。
tsTry
functionlen (s : string): number;functionlen (arr : any[]): number;functionlen (x : any) {returnx .length ;}
この関数は問題ありません。文字列または配列で呼び出すことができます。ただし、文字列または配列である可能性のある値で呼び出すことはできません。TypeScriptは関数呼び出しを単一のオーバーロードにしか解決できないためです。
tsTry
len (""); // 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]);
両方のオーバーロードの引数の数と戻り値の型が同じであるため、代わりにオーバーロードされていないバージョンの関数を記述できます。
tsTry
functionlen (x : any[] | string) {returnx .length ;}
これははるかに優れています!呼び出し元はどちらの種類の値でもこれを使用でき、さらに、正しい実装シグネチャを考え出す必要もありません。
可能な場合は、常にオーバーロードではなく、ユニオン型のパラメータを優先してください。
関数内で`this`を宣言する
TypeScriptは、コードフロー分析を通じて、関数内の`this`が何であるかを推論します。たとえば、次のようになります。
tsTry
constuser = {id : 123,admin : false,becomeAdmin : function () {this.admin = true;},};
TypeScriptは、関数`user.becomeAdmin`に対応する`this`があり、それが外部オブジェクト`user`であることを理解しています。`this`は、多くの場合で十分ですが、`this`が表すオブジェクトをより詳細に制御する必要がある場合も多くあります。JavaScriptの仕様では、`this`という名前のパラメータを持つことはできないとされており、TypeScriptはこの構文空間を使用して、関数本体内の`this`の型を宣言できるようにしています。
tsTry
interfaceDB {filterUsers (filter : (this :User ) => boolean):User [];}constdb =getDB ();constadmins =db .filterUsers (function (this :User ) {return this.admin ;});
このパターンは、コールバックスタイルのAPIで一般的です。別のオブジェクトが通常、関数の呼び出しタイミングを制御します。この動作を得るには、アロー関数ではなく`function`を使用する必要があることに注意してください。
tsTry
interfaceDB {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
値では何も行うことができないため、より安全です。
tsTry
functionf1 (a : any) {a .b (); // OK}functionf2 (a : unknown) {'a' is of type 'unknown'.18046'a' is of type 'unknown'.. a b ();}
これは、関数型を記述する際に役立ちます。関数本体にany
値を含めることなく、任意の値を受け入れる関数を記述できるためです。
逆に、不明な型の値を返す関数を記述できます。
tsTry
functionsafeParse (s : string): unknown {returnJSON .parse (s );}// Need to be careful with 'obj'!constobj =safeParse (someRandomString );
never
いくつかの関数は*決して*値を返しません。
tsTry
functionfail (msg : string): never {throw newError (msg );}
never
型は、*決して*観測されない値を表します。戻り値の型では、これは関数が例外をスローするか、プログラムの実行を終了することを意味します。
never
は、TypeScriptがユニオンに残りの何もないことを判断した場合にも表示されます。
tsTry
functionfn (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
を返します。
tsTry
functiondoSomething (f :Function ) {returnf (1, 2, 3);}
これは*型指定されていない関数呼び出し*であり、安全ではないany
戻り値の型のため、一般的に避けるべきです。
任意の関数を許可する必要があるが、呼び出すつもりがない場合は、型`() => void`の方が一般的に安全です。
Restパラメータと引数
Restパラメータ
オプションのパラメータやオーバーロードを使用して、さまざまな固定された引数の数を許容する関数を作成することに加えて、*Restパラメータ*を使用して、*無制限の*数の引数を受け取る関数を定義することもできます。
Restパラメータは、他のすべてのパラメータの後に出現し、`...`構文を使用します。
tsTry
functionmultiply (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
メソッドは任意の数の引数を取ります。
tsTry
constarr1 = [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では、次のようになります。
js
function sum({ a, b, c }) {console.log(a + b + c);}sum({ a: 10, b: 3, c: 9 });
オブジェクトの型アノテーションは、デストラクチャリング構文の後に記述します。
tsTry
functionsum ({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
型の次の実装は有効です。
tsTry
typevoidFunc = () => void;constf1 :voidFunc = () => {return true;};constf2 :voidFunc = () => true;constf3 :voidFunc = function () {return true;};
そして、これらの関数の戻り値が別の変数に代入されると、void
の型を保持します。
tsTry
constv1 =f1 ();constv2 =f2 ();constv3 =f3 ();
この動作が存在するのは、Array.prototype.push
は数値を返し、Array.prototype.forEach
メソッドは戻り値の型がvoid
の関数を期待しているにもかかわらず、次のコードが有効になるためです。
tsTry
constsrc = [1, 2, 3];constdst = [0];src .forEach ((el ) =>dst .push (el ));
もう1つの特別なケースに注意が必要です。リテラル関数定義にvoid
戻り値の型がある場合、その関数は何も返すことができません。
tsTry
functionf2 (): void {// @ts-expect-errorreturn true;}constf3 = function (): void {// @ts-expect-errorreturn true;};
void
の詳細については、他のドキュメントを参照してください。