はRuan Yifeng の TypeScript チュートリアル のメモです。メモ ディレクトリはチュートリアル ディレクトリと一致しています。このメモは不完全であり、自分自身の学習専用です。完全な学習については、Ruan Yifeng TypeScript チュートリアル または TypeScript 公式ドキュメント。
記事ディレクトリ
導入
TypeScript は JavaScript のスーパーセットと見なすことができます。つまり、後者のすべての構文を継承しています。すべての JavaScript スクリプトは TypeScript スクリプトとして扱うことができます (ただし、エラーが報告される場合があります)。また、独自の構文もいくつか追加されています。
TypeScript が JavaScript に追加する最も重要な部分は、独立した型システムです。
型システム
型は、人為的に追加されたプログラミングの制約と使用上のヒントです。目的: エラーを早期に検出すること。
例えば:
function addOne(n: number) {
return n + 1;
}
次の場合addOne("hello");
、TypeScript ではエラーが報告されますが、JS では報告されません。
動的型付けと静的型付け
JS は動的型付け言語であり、TS は静的型付け言語です。
// 例一
let x = 1;
x = "hello";
// 例二
let y = {
foo: 1 };
delete y.foo;
y.bar = 2;
JS 内にある場合、上記のコードは正しいです。バインディングは非常に弱いため、コード エラーを事前に検出することはできません。 (特定の属性が存在するかどうか、または特定の変数のデータ型を事前に知ることは不可能です)
TS では、上記のコードはエラーを報告します。 TS は、JS に静的型機能を導入します。
基本的な使い方
型宣言
JS変数に型宣言を追加します。記述方法:識別子の後に「コロン+型」。
変数:
let foo:string;
関数:
function toString(n: number): string {
return String(n);
}
エラーが報告されました:
- 変数の値が宣言された型と矛盾しています
- 変数は値が割り当てられずに使用されます (JS では、割り当てられた変数に対して undefined が返されますが、エラーは報告されません)。
型推論
型宣言は必要ありません。そうでない場合、TS は型自体を推測します。代入後に変数が別の型の値に変更され、推論された型と矛盾する場合、TS はエラーを報告します。
let foo = 123;
foo = "hello"; // 报错
コンパイル
JS の実行環境 (ブラウザおよび Node.js) が TS を認識しません。したがって、TS を実行したい場合は、まず JS に変換する必要があります。このプロセスはコンパイルです。
コンパイルについて: コンパイルすると、すべての型宣言と型関連コードが削除され、実行できる JavaScript コードのみが残り、JavaScript の実行結果は変更されません。
型チェックについて:これはコンパイル時の型チェックのみです。実行時の型チェックではありません。
値と型
「型」とは「値」を指し、「値」の属性とみなすことができます。 TS のすべての値には型があります。たとえば、3 は値であり、その型は数値です。
TypeScript コードは値ではなく型のみを扱います。 「値」に関する処理はすべてJavaScriptで完結します。
これは覚えておくことが重要です。 TypeScript プロジェクトには、実際には 2 種類のコードがあり、1 つは最下位レベルの「値コード」、もう 1 つは上位レベルの「型コード」です。前者は JavaScript 構文を使用し、後者は TypeScript の型構文を使用します。
TS のコンパイル処理では、実際にはすべての「タイプ コード」が削除され、「値コード」のみが保持されます。
TypeScript プレイグラウンド
https://www.typescriptlang.org/play
任意のタイプ、不明なタイプ、決してタイプしない
いかなるタイプ
any 型は制限がないことを意味し、この型の変数には任意の型の値を割り当てることができます。
let x: any;
x = 1; // 正确
x = "foo"; // 正确
x = true; // 正确
let x: any = "hello";
x(1); // 不报错
x.foo = 100; // 不报错
上記の例では、変数 x の値は文字列ですが、それを関数として呼び出したり、属性をオブジェクトとして読み取ったりしても、TypeScript はコンパイル時にエラーを報告しません。その理由は、x の型が any であり、TypeScript がそれを型チェックしないためです。
したがって、any 型の使用は避けてください。そうしないと、TypeScript を使用する意味が失われます。
実際の開発では、any 型は主に次の 2 つの状況に適しています。
- 特別な理由により、一部の変数の型チェックをオフにする必要がある場合は、変数の型を any に設定できます。
- 古い JavaScript プロジェクトに適応し、コードを TypeScript に迅速に移行するために、変数の型を any に設定できます。古い大規模な JavaScript プロジェクト、特に他の人のコードでは、各行に正しい型を適用することが困難です。複雑な型を持つ変数に変数を追加しても、TypeScript はコンパイル時にエラーを報告しません。
型推論の問題
開発者が型を指定せず、TypeScript が型自体を推論する必要がある変数の場合、型を推論できない場合、TypeScript は変数の型が any であると想定します。 a>。
let
および var
コマンドを使用して変数を宣言しますが、値の割り当てや型の指定を行わない場合、エラーは報告されません。
var x; // 不报错
let y; // 不报错
let と var を使用して変数を宣言する場合、値を割り当てない場合は、型を明示的に宣言する必要があります。そうしないと、セキュリティ リスクが発生する可能性があります。 たとえば、次のコードでは、 let
による宣言後に値が割り当てられていない場合、x 型は any
として推論されます。次のコードはエラーを報告しません。
let x;
x = 123;
x = {
foo: "hello" };
公害問題
任意の型の型チェックをオフにすることに加えて、別の大きな問題があります。 他のタイプの変数に代入できるため (型チェックがないため)、他の変数でエラーが発生します。 その他の変数。 「汚染」
let x: any = "hello";
let y: number;
y = x; // 不报错
y * 123; // 不报错
y.toFixed(); // 不报错
上記の例では、変数 x の型は任意で、実際の値は文字列です。変数 y の型は数値です。つまり、数値変数ですが、x が割り当てられており、エラーは報告されません。その後、変数 y はさまざまな数値演算を実行し続けるため、TypeScript はエラーを検出できず、この問題は実行時まで明らかになりません。
他の変数を正しい型で汚染し、実行時までエラーが残ることも、any 型の使用が推奨されない主な理由です。
不明なタイプ
他の変数を「汚染する」型の問題を解決するために、TypeScript 3.0 では不明な型が導入されました。これは any と同じ意味を持ち、型が未定義で任意の型である可能性があることを示しますが、いくつかの制限があります。
は any と同じです。すべての型の値を未知の型に割り当てることができます。
any との違い: 直接使用できません。
- 他の型の変数に直接代入することはできません (任意の型と不明な型を除く)。
- 未知の型変数のメソッドとプロパティを直接呼び出すことはできません
- 不明な型の変数が実行できる演算は次のように制限されています: 比較演算 (演算子
==
、===
、!=
、!==
、||
、&&
、?
)、否定演算 (演算子 < a i=8>)、 演算子および 演算子、他の演算ではエラーが報告されます!
typeof
instanceof
使用unknown
メソッド:「型の絞り込み」。つまり、エラーが発生しないように、未知の変数の型の範囲を狭めます。
のように:
let a: unknown = 1;
if (typeof a === "number") {
let r = a + 10; // 正确
}
let s: unknown = "hello";
if (typeof s === "string") {
s.length; // 正确
}
不明は、any よりも安全な代替手段と考えることができます。 any タイプを設定する必要がある場合は、通常、不明なタイプに設定することを優先する必要があります。
決して入力しないでください
TS では、「空の型」という概念が導入されています。つまり、型は空であり、値が含まれていません。 「null型」には値が存在しないため、その型はnever、つまりそのような値が存在しないと呼ばれます。
let x: never;
上の例では、変数 x の型は none であるため、それに値を代入することはできません。そうでない場合は、エラーが報告されます。
使用するシーン:
- 一部の型操作では、型操作の整合性を確保します。
- 値を返せない関数
変数に複数の型 (つまり、共用体型) がある場合、通常は分岐を使用して各型を処理する必要があります。このとき、考えられるすべてのタイプを処理した後、残りのケースは Never タイプに属します。のように:
function fn(x: string | number) {
if (typeof x === "string") {
// ...
} else if (typeof x === "number") {
// ...
} else {
x; // never 类型
}
}
他のタイプに割り当てることができます。
function f(): never {
throw new Error("Error");
}
let v1: number = f(); // 不报错
let v2: string = f(); // 不报错
let v3: boolean = f(); // 不报错
型システム
基本タイプ
ブール値、文字列、数値、bigint、シンボル、オブジェクト、未定義、null。
undefined
: 未定義を意味します。
null
: 空を意味します (ここには値がありません)。
ラッパーオブジェクトタイプ
boolean
、string
、number
有对应的包装对象类型:Boolean()
、String()
、Number()
。
メソッドを呼び出すと、文字列は自動的にラッパー オブジェクトに変換されます。 (本来、プリミティブ型の値にはメソッドはなく、オブジェクトのみにメソッドがあります)
"hello".charAt(1); // 'e'
コンストラクターとして使用すると、ラッパー オブジェクトが返されます。
const s = new String("hello");
typeof s; // 'object'
s.charAt(1); // 'e'
オブジェクト型とリテラル型のラッピング
すべてのプリミティブ型の値には、ラッパー オブジェクトとリテラルの 2 つの形式があります。
"hello"; // 字面量
new String("hello"); // 包装对象
大文字の型にはパッケージ化されたオブジェクトとリテラルの両方が含まれますが、小文字の型にはパッケージ化されたオブジェクトではなくリテラルのみが含まれます。
const s1: String = "hello"; // 正确
const s2: String = new String("hello"); // 正确
const s3: string = "hello"; // 正确
const s4: string = new String("hello"); // 报错
大文字タイプではなく、小文字タイプのみを使用することをお勧めします。
プリミティブ型が使用されるほとんどの場合、ラップされたオブジェクトの代わりにリテラルが使用されるためです。さらに、TypeScript では多くの組み込みメソッドのパラメーターが小文字の型として定義されており、大文字の型を使用するとエラーが発生します。のように:
const n1: number = 1;
const n2: Number = 1;
Math.abs(n1); // 1
Math.abs(n2); // 报错
Math.abs
の組み込みパラメータの型は小文字の number
です。大文字の Number
型が渡された場合、エラーが報告されます。
オブジェクトタイプとオブジェクトタイプ
オブジェクト (大文字)
オブジェクトに変換できる値はすべて、Object 型です。オブジェクトに変換できない 2 つの値 undefined
と null
を除き、他の値をオブジェクト タイプに割り当てることができます。
空のオブジェクト{}
は、typeObject
の省略形です。
オブジェクト (小文字)
プリミティブ型の値は含まれず、オブジェクト、配列、関数のみが含まれます。
let obj: object;
obj = {
foo: 123 };
obj = [1, 2];
obj = (a: number) => a + 1;
obj = true; // 报错
obj = "hi"; // 报错
obj = 1; // 报错
常に小文字タイプのオブジェクトを使用することをお勧めします。ほとんどの場合、オブジェクト型を使用するときは、プリミティブ型ではなく実際のオブジェクトのみを含めることが必要です。
未定義と null の特殊な機能
他のタイプの変数には、未定義または null の値を割り当てることができます。
let age: number = 24;
age = null; // 正确
age = undefined; // 正确
この理由は、JavaScript の動作との一貫性を保つためです。
場合によっては、これは開発者が望む動作ではなく、型システムの利用に役立たない場合があります。
const obj: object = undefined;
obj.toString(); // 编译不报错,运行就报错
この状況を回避するために、TypeScript にはコンパイル オプションが用意されていますstrictNullChecks
。開いた後は、 undefined
と null
はそれ自体、または any
タイプと unknown
型変数。
値の型
単一の値も型であり、「値型」と呼ばれます。値の型を他の値に割り当てることはできません。
let x: "hello";
x = "hello"; // 正确
x = "world"; // 报错
const コマンドで宣言した変数がオブジェクトに代入されている場合、値の型は推論されないことに注意してください。 const 変数をオブジェクトに代入すると、属性値を変更できます。
共用体型
共用型は、記号 | で表される、複数の型で構成される新しい型を指します。共用体型 A|B は、任意の型が A または B に属する限り、共用体型 A|B に属することを意味します。
let x: string | number;
x = 123; // 正确
x = "abc"; // 正确
ユニオン型を値型と組み合わせて、変数の複数の可能な値を表すことができます。
let setting: true | false;
let gender: "male" | "female";
let rainbowColor: "赤" | "橙" | "黄" | "绿" | "青" | "蓝" | "紫";
前述したように、コンパイル オプション strictNullChecks をオンにした後は、他のタイプの変数に未定義または null を割り当てることができなくなります。このとき、変数に実際に null 値が含まれる可能性がある場合は、共用体型を使用してそれを書き込むことができます。
let name: string | null;
name = "John";
name = null;
変数に複数の型がある場合、変数を読み取るときに、値がどの型に属するかをさらに処理する前に区別するために「型の絞り込み」を実行する必要があることがよくあります。
直接呼び出すとエラーが報告されます。
function printId(id: number | string) {
console.log(id.toUpperCase()); // 报错
}
タイプの絞り込み:
function printId(id: number | string) {
if (typeof id === "string") {
console.log(id.toUpperCase());
} else {
console.log(id);
}
}
「型削減」は、共用体型を処理するための TypeScript の標準的な方法です。複数の型が存在する可能性がある状況に遭遇した場合は、まず型を削減してからそれを処理する必要があります。実は共用体型自体も一種の「型拡張」(型拡張)とみなすことができ、処理時には「型縮小」(型縮小)が必要となります。
クロスオーバータイプ
交差タイプは、記号 & で表される、複数のタイプで構成される新しいタイプを指します。クロス タイプ A&B に属するには、どのタイプも A と B の両方に属している必要があります。つまり、クロス タイプは A と B の両方の特性を満たします。
の主な目的は、オブジェクトの構成を表すことです。 変数 obj には、属性 foo と属性 bar の両方があります。
let obj: {
foo: string } & {
bar: string };
obj = {
foo: "hello",
bar: "world",
};
新しいプロパティをオブジェクト タイプに追加するためによく使用されます。 タイプ B はクロス タイプで、A をベースに属性バーを追加するために使用されます。
type A = {
foo: number };
type B = A & {
bar: number };
コマンドを入力します
type コマンドは、タイプのエイリアスを定義するために使用されます。
type コマンドは、数値タイプの別名 Age を定義します。こうすることで、数値を使用するのと同じように、Age をタイプとして使用できます。
type Age = number;
let age: Age = 55;
エイリアスのスコープはブロックレベルのスコープです。
if (true) {
type T = number;
let v: T = 5;
} else {
type T = string;
let v: T = "hello";
}
エイリアスは式の使用をサポートし、ネストを許可します。
この例では、エイリアス Greeting はテンプレート文字列を使用して、別のエイリアス World を読み取ります。
type World = "world";
type Greeting = `hello ${
World}`;
演算子の種類
JS ではtypeof
演算子は文字列を返します。
typeof undefined; // "undefined"
typeof true; // "boolean"
typeof 1337; // "number"
typeof "foo"; // "string"
typeof {
}; // "object"
typeof parseInt; // "function"
typeof Symbol(); // "symbol"
typeof 127n; // "bigint"
TS で返されるのは TS タイプです。
const a = {
x: 0 };
type T0 = typeof a; // { x: number }
type T1 = typeof a.x; // number
同じコード部分に 2 つの typeof 演算子が存在する場合があります。1 つは値関連の JavaScript コード部分で使用され、もう 1 つは型関連の TypeScript コード部分で使用されます。のように:
1 つ目は型の操作で、2 つ目は値の操作です。
let a = 1;
let b: typeof a;
if (typeof a === "number") {
b = a;
}
JavaScript の typeof は JavaScript の規則に従い、TypeScript の typeof は TypeScript の規則に従います。両者の重要な違いは、前者はコンパイル後に保持されるのに対し、後者は完全に削除されることです。上記の例のコードのコンパイル結果は次のとおりです。
let a = 1;
let b;
if (typeof a === "number") {
b = a;
}
TypeScript では、typeof のパラメータには識別子のみを指定でき、演算を必要とする式は指定できないと規定されています。 typeof コマンドのパラメータを type にすることはできません。
タイプの互換性
型 A の値を型 B に割り当てることができる場合、型 A は型 B のサブタイプと呼ばれます。
例: typenumber は typenumber|string のサブタイプです。
type T = number | string;
let a: number = 1;
let b: T = a;
親タイプを使用できる場合はどこでも、サブタイプを使用できますが、その逆はできません。
let a: "hi" = "hi";
let b: string = "hello";
b = a; // 正确
a = b; // 报错