一.タイプ
関数のタイプは 2 つの部分に分かれます:
-
パラメータ:各パラメータのタイプ
-
戻り値:戻り値のタイプ
例えば:
// 具名関数
function add(x: number, y: number): number {
return x + y;
}
// 匿名関数
let myAdd = function(x: number, y: number): number { return x + y; };
タイプ付きの関数宣言は関数のタイプ情報を十分に表現できますが、再利用できません。では、関数のタイプを再利用する方法はありますか?
あります。タイプを抽出すれば再利用できます。とりあえずタイプ記述と呼びます
タイプ記述
アロー関数構文を通じて関数のタイプを記述できます:
let myAdd: (x: number, y: number) => number =
function(x: number, y: number): number { return x + y; };
アロー(=>)の左側はパラメータとそのタイプで、右側は戻り値のタイプです。これらはすべて構文構造の一部であり、省略不可です:
// 戻り値なし
let log: (msg: string) => void = function(msg) {
console.log(msg);
};
// パラメータなし
let createLogger: () => object = function() {
return { log };
};
// パラメータも戻り値もなし
let logUa: () => void = log.bind(this, navigator.userAgent);
P.S.上記の例ではタイプを 1 つしか宣言していないことに注意してください。右側の匿名関数のタイプは左側のタイプ宣言に基づいて自動的に推論できるためです。これを文脈タイプ推論(contextual typing)と呼びます
また、タイプ記述内のパラメータ名は可読性のためのみであり、タイプ記述中のパラメータ名が実際のパラメータ名と一致する必要はありません。例えば:
let myAdd: (baseValue: number, increment: number) => number =
function(x: number, y: number): number { return x + y; };
P.S.実際には、関数タイプを記述するもう 1 つの方法があります:インターフェースです。詳細は インターフェース_TypeScript ノート 3 を参照
二.パラメータ
オプションパラメータ
JavaScript ではパラメータはデフォルトですべてオプションです(渡さない場合はデフォルトで undefined)。TypeScript では各パラメータは必須とみなされます。オプションパラメータを明示的に宣言しない限り:
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
オプションプロパティ の構文と類似しており、パラメータ名の直後の ? はそのパラメータがオプションであることを示し、オプションパラメータは必須パラメータの後に出現する必要がある と要求されます(したがって firstName をオプションにし、lastName を必須にしたい場合は、パラメータの順序を変更するしかありません)
デフォルトパラメータ
デフォルトパラメータの構文は [ES 仕様](/articles/默认参数和不定参数-es6 笔记 4/#articleHeader3) と一致します。例えば:
function buildName(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
}
意味から見ると、デフォルトパラメータは当然オプションです(記入しない場合はデフォルト値を使用)。したがって、デフォルトパラメータは特殊なオプションパラメータとみなせます。タイプ記述も互換性があります:
let buildName: (firstName: string, lastName?: string) => string;
// オプションパラメータ
buildName = function(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
};
// デフォルトパラメータ
buildName = function(firstName: string, lastName = "Smith") {
return firstName + " " + lastName;
};
両者のタイプは完全に一致するため、タイプ記述はデフォルトパラメータを完全に表現できません(オプションの意味のみを表現でき、デフォルト値は失われます)
もう 1 つの違いは、デフォルトパラメータは必須パラメータの後に出現する必要がないことです。例えば:
function buildName(firstName = "Will", lastName: string) {
return firstName + " " + lastName;
}
buildName(undefined, "Adams");
undefined を明示的に渡してプレースホルダーとします。詳細は [三。デフォルトパラメータ](/articles/默认参数和不定参数-es6 笔记 4/#articleHeader3) を参照
残りのパラメータ
[ES6 可変長パラメータ](/articles/默认参数和不定参数-es6 笔记 4/#articleHeader2) の構文と一致します:
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
残りのパラメータもオプションであり、無制限の数のオプションパラメータ に相当します:
Rest parameters are treated as a boundless number of optional parameters.
また、タイプ記述中でも同じ構文が採用されています:
let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;
三.this
this は JavaScript でそれほど簡単に扱えません。例えば:
class Cat {
constructor(public name: string) {}
meow() { console.log(`${this.name} meow~`); }
}
let cat = new Cat('Neko');
// クリックでトリガーされる log 中で、name が失われる
document.body.addEventListener('click', cat.meow);
this のタイプ
特別に、TypeScript は this のタイプを記述できます。例えば:
class Cat {
constructor(public name: string) {}
meow(this: Cat) { console.log('meow~'); }
}
class EventBus {
on(type: string, handler: (this: void, ...params) => void) {/* ... */}
}
new EventBus().on('click', new Cat('Neko').meow);
その中で this は偽パラメータであり、最初のパラメータとして出現する必要があります:
this parameters are fake parameters that come first in the parameter list of a function.
this も通常のパラメータと同じようにタイプチェックされ、類似のエラーを事前に暴露できます:
Argument of type '(this: Cat) => void' is not assignable to parameter of type '(this: void, ...params: any[]) => void'.
P.S.また、--noImplicitThis コンパイルオプションを有効にし、すべての this に明示的なタイプ宣言を強制要求できます
四.オーバーロード
Java のオーバーロードに類似:
Method Overloading: This allows us to have more than one method having the same name, if the parameters of methods are different in number, sequence and data types of parameters.
(Types of polymorphism in java- Runtime and Compile time polymorphism から引用)
簡潔に言えば、同名関数の異なるバージョンを共存させられます。異なるバージョンはパラメータの差異に現れます:
-
パラメータ数
-
パラメータ順序
-
パラメータタイプ
この 3 つの特徴のうち 1 つでも異なればオーバーロードとみなされます。すべて同じ場合、重複宣言されたメソッド(Duplicate Method)とみなされ、コンパイルエラーがスローされます:
// Java
public class Addition {
// Compile Time Error - Duplicate method sum(int, int)
int sum(int a, int b) {
return a+b;
}
// Compile Time Error - Duplicate method sum(int, int)
void sum(int a, int b) {
System.out.println(a+b);
}
}
TypeScript にもオーバーロードの概念がありますが、Java のオーバーロードとはいくつかの違いがあります。例えば:
class Addition {
sum(a: number, b: number): number {
return a + b;
}
sum(a: number[]): number {
return a.reduce((acc, v) => acc + v, 0);
}
}
非常に合理的に見えますが、TypeScript ではエラーが報告されます:
Duplicate function implementation.
コンパイル結果は以下の通りです(TypeScript のコンパイルエラーはコード生成に影響しません。詳細は [タイプシステム](/articles/typescript 简介-typescript 笔记 1/#articleHeader6) を参照):
var Addition = /** @class */ (function () {
function Addition() {
}
Addition.prototype.sum = function (a, b) {
return a + b;
};
Addition.prototype.sum = function (a) {
return a.reduce(function (acc, v) { return acc + v; }, 0);
};
return Addition;
}());
JavaScript はオーバーロードをサポートしていないため、(同一スコープ内の)メソッドは先に宣言された同名メソッドを上書きします。関数シグネチャが同じかどうかに関わらず。したがって、TypeScript でのオーバーロード能力は制限され、タイプ上でのみ現れます:
function sum(a: number, b: number): number;
function sum(a: number[]): number;
function sum(a, b?) {
if (Array.isArray(a)) {
a.reduce((acc, v) => acc + v, 0);
}
return a + b;
}
同様に、これらのオーバーロードタイプ宣言はコンパイル時のみに作用するため、[パターンマッチング](/articles/基础语法-haskell 笔记 1/#articleHeader18) に類似した特性もあります:
function sum(a: any, b: any): any;
function sum(a: number, b: number): number;
function sum(a, b) {
return Number(a) + Number(b);
}
// ここで value は any タイプ
let value = sum(1, 2);
上記の例では、先に宣言されたより広範な any バージョンが正常にマッチし、したがって予想通りにより正確な number バージョンにマッチしませんでした。
It looks at the overload list, and proceeding with the first overload attempts to call the function with the provided parameters. If it finds a match, it picks this overload as the correct overload.
したがって、最も広範なバージョンを最後に宣言するべきです:
it's customary to order overloads from most specific to least specific.
コメントはまだありません