TypeScript 型システム
この章では、TypeScript 型システムの概要を説明します。
TypeScript は JavaScript の型を継承し、これに基づいて独自の型システムを定義します。
基本的なタイプ
概要
JavaScript 言語 (TypeScript ではないことに注意) は値を 8 つの型に分割します。
-ブール値
- 弦
- 番号 -bigint -シンボル
- 物体
- 未定義 -null
TypeScript は JavaScript の型設計を継承しており、上記 8 種類が TypeScript の基本型と言えます。
上記の型の名前はすべて小文字であり、最初の文字が大文字である「Number」、「String」、「Boolean」などは、型名ではなく、JavaScript 言語の組み込みオブジェクトであることに注意してください。
さらに、未定義と null は、使用される場所に応じて、値と型の両方として使用できます。
これら 8 つの基本型は TypeScript 型システムの基礎であり、複合型はこれらから構成されます。
以下にそれらについて簡単に紹介します。
ブール型
boolean
タイプには、true
と false
の 2 つのブール値のみが含まれます。
const x:boolean = true;
const y:boolean = false;
上記の例では、変数 x
と y
はブール型に属します。
文字列型
string
タイプにはすべての文字列が含まれます。
const x:string = 'こんにちは';
const y:string = `${x} ワールド`;
上記の例では、通常の文字列とテンプレート文字列の両方が文字列型に属します。
数値型
「number」タイプには、すべての整数と浮動小数点数が含まれます。
const x:数値 = 123;
const y:number = 3.14;
const z:number = 0xffff;
上の例では、整数、浮動小数点数、および 10 進数以外の数値はすべて数値型に属します。
bigint 型
bigint 型には、すべての大きな整数が含まれます。
const x:bigint = 123n;
const y:bigint = 0xffffn;
上記の例では、変数 x
と y
は bigint 型に属します。
bigint は数値型と互換性がありません。
const x:bigint = 123; // エラーレポート
const y:bigint = 3.14; // エラーレポート
上記の例では、「bigint」型が整数または小数に割り当てられている場合、エラーが報告されます。
bigint 型は ES2020 標準によって導入されたことに注意してください。この型を使用する場合、TypeScript によってコンパイルされるターゲット JavaScript バージョンは ES2020 より低くすることはできません (つまり、コンパイル パラメーター target
は es2020
より低くてはなりません)。
シンボルの種類
シンボル タイプには、すべてのシンボル値が含まれます。
const x:symbol = Symbol();
上の例では、Symbol()
関数の戻り値は、symbol 型です。
シンボル タイプの詳細については、「シンボル」の章を参照してください。
オブジェクトタイプ
JavaScript の設計によれば、オブジェクト タイプにはすべてのオブジェクト、配列、関数が含まれます。
const x:object = { foo: 123 };
const y:オブジェクト = [1, 2, 3];
const z:オブジェクト = (n:数値) => n + 1;
上の例では、オブジェクト、配列、関数はすべてオブジェクト タイプに属します。
未定義型、null 型
unknown と null は 2 つの別個の型であり、それぞれの値は 1 つだけです。
未定義型には、値「未定義」が 1 つだけ含まれます。これは、定義されていないことを意味します (つまり、定義はまだ与えられておらず、将来定義される可能性があります)。
x:未定義 = 未定義にしてみましょう。
上の例では、変数 x
の型は未定義です。 2 つの「未定義」のうち、1 つ目は型、2 つ目は値です。
null 型には、値 null
が 1 つだけ含まれます。これは、空であることを意味します (つまり、ここには値がありません)。
const x:null = null;
上の例では、変数 x
の型は null です。
型が宣言されていない変数に値 unknown
または null
が割り当てられている場合、コンパイル設定 noImplicitAny
および strictNullChecks
がオフになっている場合、それらの型は any
として推論されることに注意してください。
// noImplicitAny と strictNullChecks をオフにする
let a = 未定義; // 任意
const b = 未定義;
let c = null // 任意;
const d = null // 任意;
これを回避したい場合は、コンパイル オプション strictNullChecks
をオンにする必要があります。
//コンパイル設定を開く strictNullChecks
let a = 未定義 // 未定義;
const b = 未定義;
let c = null // null;
const d = null // null;
上記の例では、コンパイル設定 strictNullChecks
をオンにすると、unknown
に割り当てられた変数は undefined
型であると推論され、null
に割り当てられた変数は null
型であると推論されます。
オブジェクトタイプのパッケージ化
オブジェクトのパッケージ化の概念
JavaScript の 8 種類のうち、実際には unknown
と null
は 2 つの特別な値で、object
は複合型で、残りの 5 つは最も基本的で割り切れない型を表すプリミティブ値です。
-ブール値
- 弦
- 番号 -bigint -シンボル
上記の 5 つのプリミティブ型の値には、対応するラッパー オブジェクトがあります。いわゆる「パッケージングオブジェクト」とは、必要に応じてこれらの値を自動的に生成するオブジェクトを指します。
'hello'.charAt(1) // 'e'
上の例では、文字列 hello
が charAt()
メソッドを実行します。ただし、JavaScript 言語ではオブジェクトのみがメソッドを持ち、プリミティブ値自体にはメソッドがありません。このコード行が実行できる理由は、メソッドが呼び出されるときに文字列が自動的にラッパー オブジェクトに変換され、charAt()
メソッドが実際にラッパー オブジェクト上で定義されるためです。
この設計により、文字列処理が大幅に容易になり、プリミティブ型の値をオブジェクト インスタンスに手動で変換する手間が省けます。
5 種類のパッケージング オブジェクトのうち、シンボル型と bigint 型はパッケージング オブジェクトを直接取得できません (つまり、Symbol()
と BigInt()
はコンストラクターとして使用できません) が、残りの 3 つは可能です。
ブール値()
文字列()
数値()
上記 3 つのコンストラクターは、実行後に特定のプリミティブ型値のパッケージング オブジェクトを直接取得できます。
const s = 新しい String('hello');
typeof s // 'オブジェクト'
s.charAt(1) // 'e'
上の例では、s
は文字列 hello
のパッケージ化オブジェクトであり、typeof
演算子は string
ではなく object
を返しますが、本質的には依然として文字列であり、すべての文字列メソッドは次のようになります。使用済み。
String()
は、コンストラクターとして使用される (つまり、new
コマンドで呼び出される) 場合にのみラッパー オブジェクトを返すことに注意してください。 (「new」コマンドを使用せずに) 通常の関数として使用すると、戻り値は通常の文字列になります。他の 2 つのコンストラクター Number()
と Boolean()
についても同様です。
オブジェクト型とリテラル型のパッケージ化
ラッパー オブジェクトが存在するため、すべてのプリミティブ型の値には、ラッパー オブジェクトとリテラルという 2 つの状況があります。
'こんにちは' // リテラル
new String('hello') // ラッパーオブジェクト
上記の例では、最初の行はリテラル、2 行目はラッパー オブジェクトで、どちらも文字列です。
これら 2 つの状況を区別するために、TypeScript は 5 つのプリミティブ型のそれぞれに大文字と小文字の型を提供します。
-ブール値とブール値
- 文字列と文字列
- 数字と数字
- BigInt と bigint
- 記号と記号
このうち、大文字タイプにはパッケージング オブジェクトとリテラルの両方が含まれますが、小文字タイプにはリテラルのみが含まれ、パッケージング オブジェクトは含まれません。
const s1:String = 'hello'; // 正しい
const s2:String = new String('hello'); // 正しい
const s3:string = 'hello' // 正しい。
const s4:string = new String('hello'); // エラーレポート
上記の例では、「String」型を文字列リテラルまたはラッパー オブジェクトに割り当てることができます。ただし、「string」型はリテラル値にのみ割り当てることができ、ラップされたオブジェクトに割り当てるとエラーが報告されます。
大文字タイプではなく、小文字タイプのみを使用することをお勧めします。プリミティブ型が使用されるほとんどの場合、ラップされたオブジェクトの代わりにリテラルが使用されるためです。さらに、TypeScript では多くの組み込みメソッドのパラメーターが小文字の型として定義されており、大文字の型を使用するとエラーが発生します。
const n1:数値 = 1;
const n2:数値 = 1;
Math.abs(n1) // 1
Math.abs(n2) // エラー
上記の例では、Math.abs()
メソッドのパラメータの型は小文字の number
として定義されており、大文字の Number
型が渡されるとエラーが報告されます。
前節で述べたように、Symbol()
と BigInt()
という 2 つの関数はコンストラクタとして使用できないため、次のような書き方をしない限り、シンボル型と bigint 型のラッパー オブジェクトを直接取得する方法はありません。使用済み。しかし、それらには使用シナリオがないため、「Symbol」と「BigInt」の 2 つの型が存在しますが、それらを使用する理由はまったくありません。
a = オブジェクト(シンボル());
b = Object(BigInt()); とします。
上記例ではSymbolとBigIntのパッケージ化オブジェクトが得られますが、使用する上では意味がありません。
現在、TypeScript では symbol
と Symbol
の間に違いはなく、同じことが bigint
と BigInt
にも当てはまります。これが公式の見落としかどうかはわかりません。常に小文字の symbol
と bigint
を使用し、大文字の Symbol
と BigInt
は使用しないことをお勧めします。
オブジェクトタイプとオブジェクトタイプ
TypeScript のオブジェクト タイプには、大文字の Object
と小文字の object
も含まれます。
オブジェクトの種類
大文字の「Object」タイプは、JavaScript 言語の一般化されたオブジェクトを表します。オブジェクトに変換できる値はすべて「Object」型であり、ほぼすべての値をカバーします。
let obj:オブジェクト;
obj = true;
obj = 'こんにちは';
オブジェクト = 1;
obj = { foo: 123 };
obj = [1, 2];
obj = (a:数値) => a + 1;
上の例では、プリミティブ型の値、オブジェクト、配列、関数はすべて正当な Object
型です。
実際には、オブジェクトに変換できない unknown
と null
の 2 つの値を除いて、他の値はすべて Object
型に割り当てることができます。
let obj:オブジェクト;
obj = 未定義; // エラーレポート
obj = null // エラーレポート
上記の例では、「Object」型に「unknown」と「null」が割り当てられている場合、エラーが報告されます。
また、空のオブジェクト {}
は Object
型の略称であるため、Object
を使用する場合は空のオブジェクトに置き換えられることが多いです。
obj:{};
obj = true;
obj = 'こんにちは';
オブジェクト = 1;
obj = { foo: 123 };
obj = [1, 2];
obj = (a:数値) => a + 1;
上記の例では、変数 obj
の型は空のオブジェクト {}
であり、これは Object
型を表します。
明らかに、すべてを包括するオブジェクト型は直感的にも使いやすいものでもありません。
オブジェクトタイプ
小文字の「object」型は、JavaScript の狭いオブジェクト、つまり、オブジェクト、配列、関数のみを含み、プリミティブ型の値は含みません。
オブジェクトをみましょう:オブジェクト;
obj = { foo: 123 };
obj = [1, 2];
obj = (a:数値) => a + 1;
obj = true; // エラーレポート
obj = 'hi' // エラーレポート
obj = 1; // エラーレポート
上の例では、「object」型にはプリミティブ型の値は含まれず、オブジェクト、配列、関数のみが含まれます。
ほとんどの場合、オブジェクト型を使用するときは、プリミティブ型ではなく実際のオブジェクトのみを含めることが必要です。したがって、常に小文字の object
を使用し、大文字の Object
を使用しないことをお勧めします。
大文字の Object
タイプと小文字の object
タイプには、JavaScript 組み込みオブジェクトのネイティブ プロパティとメソッドのみが含まれており、これら 2 つのタイプにはユーザー定義のプロパティとメソッドが存在しないことに注意してください。
const o1:Object = { foo: 0 };
const o2:object = { foo: 0 };
o1.toString() // 正しい
o1.foo // エラーレポート
o2.toString() // 正しい
o2.foo // エラーレポート
上記の例では、toString()
はオブジェクトのネイティブ メソッドであり、正しくアクセスできます。 foo
はカスタム属性であり、アクセスするとエラーが報告されます。オブジェクトのカスタム プロパティを記述する方法の詳細については、「オブジェクト タイプ」の章を参照してください。
未定義と null の特殊性
「unknown」と「null」は両方とも値であり、型です。
値として、これらには特別な機能があります。他のタイプの変数には、値 unknown
または null
を割り当てることができます。
年齢:数値 = 24 とします。
年齢 = null // 正しい;
年齢 = 未定義 // 正しい;
上記のコードでは、変数 age
の型は number
ですが、値を null
または unknown
に代入してもエラーは報告されません。
これは、「unknown」と「null」が「number」型に含まれているためではなく、JavaScript の動作との一貫性を保つために、任意の型の変数を「unknown」と「null」に代入できるように設計されています。
JavaScript の動作では、変数が「unknown」に等しい場合は値が割り当てられていないことを意味し、変数が「null」に等しい場合は値が空であることを意味します。したがって、TypeScript では、任意のタイプの変数をこれら 2 つの値に割り当てることができます。
しかし、これは開発者が望む動作ではなく、型システムの利用に役立たない場合もあります。
const obj:object = 未定義;
obj.toString() // コンパイル時にはエラーは報告されませんが、実行時にはエラーが報告されます。
上の例では、変数 obj
は unknown
に等しいため、コンパイル中にエラーは報告されません。ただし、実際の実行では、「unknown」はオブジェクトではなく、このメソッドを持たないため、「obj.toString()」を呼び出すときにエラーが報告されます。
この状況を回避し、エラーを早期に検出するために、TypeScript にはコンパイル オプション strictNullChecks
が用意されています。このオプションがオンになっている限り、「unknown」と「null」を他の型の変数に割り当てることはできません (「any」型と「unknown」型を除く)。
以下は、このコンパイル オプションをオンにする tsc コマンドの例です。
// tsc --strictNullChecks app.ts
年齢:数値 = 24 とします。
年齢 = null // エラー;
age = 未定義; // エラーレポート
上記の例では、「--strictNullChecks」をオンにすると、「number」型の変数「age」を「unknown」と「null」に代入できなくなります。
このオプションは設定ファイルtsconfig.json
内に以下のように記述されます。
{
"コンパイラーオプション": {
"strictNullChecks": true
// ...
}
}
「strictNullChecks」をオンにすると、「unknown」と「null」の 2 つの値を互いに割り当てることができなくなります。
// strictNullChecks をオンにする
let x:unknown = null // エラーを報告します。
let y:null = unknown; // エラーレポート
上記の例では、タイプ unknown
の変数に値 null
が割り当てられている場合、またはタイプ null
の変数に値 unknown
が割り当てられている場合、エラーが報告されます。
つまり、「strictNullChecks」をオンにした後は、「unknown」と「null」はそれ自体、または「any」型と「unknown」型の変数にのみ代入できます。
x:any = 未定義にしてみましょう。
y:unknown = null にします。
値の型
TypeScript では、「値の型」と呼ばれる、単一の値も型であると規定されています。
x:'こんにちは';
x = 'こんにちは' // 正しいです。
x = 'ワールド'; // エラー
上の例では、変数 x
の型は文字列 hello
なので、この文字列にのみ代入できます。他の文字列に代入すると、エラーが報告されます。
TypeScript が型を推論するとき、「const」コマンドで宣言された変数に遭遇したとき、コード内で型が指定されていない場合、その変数は値型であると推論されます。
// xの型は「https」です
const x = 'https';
// y の型は文字列です
const y:string = 'https';
上記の例では、変数 x
が const
コマンドで宣言されており、TypeScript はその型が string
型ではなく値 https
であると推測します。
const
コマンドで宣言された変数は、定数と同等であり、一度宣言すると変更できないため、この推論は合理的です。値タイプは、他の値に割り当てることができないことを意味します。
const
コマンドで宣言された変数にオブジェクトが割り当てられている場合、値の型は推論されないことに注意してください。
// x の型は { foo:number }
const x = { foo: 1 };
上記の例では、変数 x
は値の型として推論されませんが、属性 foo
の型は number
として推論されます。これは、JavaScript ではオブジェクトに「const」変数を代入するとプロパティの値を変更できるためです。
値の型によって、奇妙なエラーが発生する可能性があります。
const x:5 = 4 + 1; // エラー
上記の例では、等号の左側の型は値 5' であり、等号の右側の型は
4 + 1であり、TypeScript はそれを
numberとして推論します。
5は
number のサブタイプであり、
numberは
5` の親タイプであるため、親タイプを子タイプに割り当てることはできないため、エラーが報告されます (詳細については、この章の後半を参照してください)。 。
ただし、その逆も可能で、サブタイプを親タイプに割り当てることができます。
x:5 = 5 とします。
y:数値 = 4 + 1; とします。
x = y // エラー
y = x; // 正しい
上記の例では、変数 x
はサブタイプに属し、変数 y
は親タイプに属します。サブタイプ x
を親タイプ y
に割り当てることはできませんが、その逆は可能です。
サブタイプを親タイプの値に割り当て可能にする必要がある場合は、タイプ アサーションを使用する必要があります (詳細については、「タイプ アサーション」の章を参照してください)。
const x:5 = (4 + 1) として 5;
上記の例では、4 + 1
の後に as 5
を追加すると、コンパイラに 4 + 1
の型を値の型 5
と見なすことができるため、エラーは報告されません。
値が 1 つだけ含まれる値型はほとんど役に立ちません。実際の開発では、複数の値を組み合わせて共用体型として使用することがよくあります。
ユニオンタイプ
共用型は、複数の型で構成される新しい型を指し、記号 |
で表されます。
共用体型 A|B
は、任意の型が A
または B
に属する限り、それは共用体型 A|B
に属することを意味します。
x:文字列|数値;
x = 123; // 正しい
x = 'abc' // 正しい
上記の例では、変数 x
は共用体型 string|number
であり、その値は文字列または数値のいずれかであることを意味します。
ユニオン型を値型と組み合わせて、変数の複数の可能な値を表すことができます。
設定を許可します: true|false;
性別を許可します:'男性'|'女性';
レインボーカラー:'赤'|'オレンジ'|'黄色'|'緑'|'緑'|'青'|'紫';
上記の例はすべて値型で構成された共用体型であり、変数の値の範囲を明確に表現しています。このうち、「true|false」は実際にはブール型の「boolean」です。
前に述べたように、コンパイル オプション strictNullChecks
をオンにすると、他のタイプの変数を unknown
または null
に割り当てることができなくなります。このとき、変数に実際に null 値が含まれる可能性がある場合は、共用体型を使用してそれを書き込むことができます。
名前:文字列|null;にします。
名前 = 'ジョン';
名前 = null;
上の例では、変数 name
の値は文字列または null
にすることができます。
複数行の記述を容易にするために、共用体型の最初のメンバーの前に垂直バー |
を追加することもできます。
x にしましょう:
|「ひとつ」
|「2」
|「3」
| '4';
上の例では、共用体型の最初のメンバー 'one' の前に垂直バーが追加されます。
変数に複数の型がある場合、変数を読み取るときに、値がどの型に属するかをさらに処理する前に区別するために「型の絞り込み」を実行する必要があることがよくあります。
関数 printId(
ID:番号|文字列
) {
console.log(id.toUpperCase()); // エラーレポート
}
上の例では、パラメータ変数 id
は数値または文字列である可能性があります。この場合、この変数に対して toUpperCase()
メソッドを直接呼び出すとエラーが報告されます。これは、このメソッドが文字列に対してのみ存在し、エラーが発生するためです。数値の場合は存在しません。
解決策は、パラメータ id
の型を減らし、処理前にその型を決定することです。
関数 printId(
ID:番号|文字列
) {
if (ID の種類 === '文字列') {
console.log(id.toUpperCase());
} それ以外 {
コンソール.ログ(id);
}
}
上記の例では、関数本体は変数 id
の型を決定し、それが文字列の場合は、それに対して toUpperCase()
メソッドを実行します。
「型削減」は、共用体型を処理するための TypeScript の標準方法です。複数の型が存在する可能性がある状況に遭遇した場合は、まず型を削減してからそれを処理する必要があります。実は共用体型自体も一種の「型拡張」(型拡張)とみなすことができ、処理時には「型縮小」(型縮小)が必要となります。
「型の絞り込み」の別の例を次に示します。
関数 getPort(
スキーム: 'http'|'https'
) {
スイッチ (スキーム) {
'http'の場合:
80を返します。
ケース「https」:
443 を返します。
}
}
上記の例では、パラメーター変数 scheme
が関数本体内で型が絞り込まれており、異なる値の型に応じて異なる結果が返されます。
クロスオーバータイプ
交差タイプとは、複数のタイプで構成される新しいタイプを指し、記号「&」で表されます。
クロス型「A&B」とは、クロス型「A&B」に属するためには、「A」と「B」の両方に属さなければならない、つまり「A」と「B」の両方の特性を満たすクロス型を意味する。
let x:number&string;
上の例では、変数 x
は数値と文字列の両方です。これはもちろん不可能なので、TypeScript は x
の型が実際には never
であると判断します。
交差タイプの主な用途は、オブジェクトの構成を表すことです。
オブジェクトをみましょう:
{ foo: 文字列 } &
{ バー: 文字列 };
オブジェクト = {
ふー:「こんにちは」、
バー:「ワールド」
};
上記の例では、変数 obj
は属性 foo
と属性 bar
の両方を持っています。
クロス タイプは、オブジェクト タイプに新しいプロパティを追加するためによく使用されます。
type A = { foo: 数値 };
type B = A & { バー: 数値 };
上記の例では、タイプ B
はクロス タイプであり、属性 bar
を A
に追加するために使用されます。
コマンドを入力します
type
コマンドは、タイプのエイリアスを定義するために使用されます。
年齢 = 数値を入力します。
年齢を設定します:年齢 = 55;
上の例では、type
コマンドは、number
型のエイリアス Age
を定義しています。これにより、「number」を使用するのと同じように、「Age」をタイプとして使用できるようになります。
エイリアスを使用すると、型の名前がより意味のあるものになり、コードの可読性が向上し、複雑な型がより使いやすくなり、後で変数の型を変更しやすくなります。
エイリアスでは重複した名前を使用できません。
タイプ Color = 'red';
type Color = 'blue' // エラーレポート
上記の例では、同じエイリアス Color
が 2 回宣言された場合、エラーが報告されます。
エイリアスのスコープはブロックレベルのスコープです。これは、コード ブロック内で定義されたエイリアスが外部には影響を及ぼさないことを意味します。
タイプ Color = 'red';
if (Math.random() < 0.5) {
タイプ Color = '青';
}
上記の例では、「if」コード ブロック内の型エイリアス「Color」は外部の「Color」とは異なります。
エイリアスは式の使用をサポートしており、エイリアスを定義するときに別のエイリアスを使用することもできます。つまり、エイリアスではネストが可能です。
World = "ワールド" と入力します。
type Greeting = `hello ${World}`;
上記の例では、エイリアス Greeting
はテンプレート文字列を使用して別のエイリアス World
を読み取ります。
type
コマンドは型関連のコードであり、JavaScript にコンパイルされると完全に削除されます。
演算子の種類
JavaScript 言語では、typeof 演算子はオペランドの型を表す文字列を返す単項演算子です。
typeof 'foo' // '文字列';
上の例では、typeof
演算子は、タイプが string
である文字列 foo
を返します。
typeof のオペランドは値であることに注意してください。
JavaScript では、「typeof」演算子は 8 つの結果のみを返すことができ、それらはすべて文字列です。
タイプは未定義です // "未定義"
typeof true; // "ブール値"
typeof 1337; // "数値"
typeof "foo"; // "文字列";
typeof {}; // 「オブジェクト」
typeof parseInt; // 「関数」
typeof Symbol(); // 「シンボル」
typeof 127n // "bigint"
上の例は、JavaScript 言語の「typeof」演算子によって返される 8 つの可能な結果です。
TypeScript は「typeof」演算子を型演算に移植しますが、そのオペランドは依然として値ですが、返されるのは文字列ではなく、値の TypeScript 型です。
const a = { x: 0 };
type T0 = typeof a; // { x: 数値 }
type T1 = typeof a.x // 数値;
上記の例では、typeof a
は、変数 a
({ x:number }
) の TypeScript 型を返すことを意味します。同様に、typeof a.x
は属性 x
(number
) の型を返します。
この「typeof」の使用法は TypeScript 型を返すため、型操作 (つまり、型関連のコード) でのみ使用でき、値操作では使用できません。
言い換えれば、同じコード部分に 2 つの typeof
演算子が存在する可能性があり、1 つは値関連の JavaScript コード部分で使用され、もう 1 つは型関連の TypeScript コード部分で使用されます。
a = 1 とします。
b: a の型をみましょう。
if (typeof a === '数値') {
b = a;
}
上記の例では、2 つの typeof
が使用されています。1 つ目は型演算で、2 つ目は値演算です。これらは異なるものであり、混同しないでください。
JavaScript の typeof は JavaScript の規則に従い、TypeScript の typeof は TypeScript の規則に従います。両者の重要な違いは、前者はコンパイル後に保持されるのに対し、後者は完全に削除されることです。
上記の例のコードのコンパイル結果は次のとおりです。
a = 1 とします。
b にしましょう。
if (typeof a === '数値') {
b = a;
}
上記の例では、元のコードの 2 番目のタイプのみが保持され、最初のタイプは削除されます。
JavaScript の値の操作はコンパイル中に実行されないため、TypeScript では、typeof のパラメーターには識別子のみを使用でき、操作を必要とする式は使用できないと規定しています。
type T = typeof Date(); // エラー
typeof のパラメータは値式にすることができず、Date()
では結果を知るための操作が必要なため、上記の例ではエラーが報告されます。
さらに、「typeof」コマンドのパラメータを型にすることはできません。
タイプ 年齢 = 数値;
type MyAge = typeof Age // エラーレポート;
上記の例では、「Age」は型のエイリアスであり、「typeof」コマンドのパラメータとして使用するとエラーが報告されます。
typeof は非常に重要な TypeScript 演算子です。場合によっては、特定の変数 foo
の型が不明な場合、その型を取得するために typeof foo
を使用できます。
ブロックレベルの型宣言
TypeScript はブロック レベルの型宣言をサポートしています。つまり、型はコード ブロック内 (中括弧で示されています) で宣言でき、現在のコード ブロック内でのみ有効です。
if (true) {
T = 数値を入力します。
v:T = 5 とします。
} それ以外 {
タイプ T = 文字列;
v:T = 'こんにちは' とします。
}
上の例では、2 つのコード ブロックがあり、それぞれにタイプ T
の宣言があります。どちらの宣言も、それぞれのコード ブロック内でのみ有効であり、コード ブロックの外では効果がありません。
型の互換性
TypeScript の型には互換性関係があり、一部の型は他の型と互換性があります。
タイプ T = 数値|文字列;
a:数値 = 1 とします。
b:T = a;
上記の例では、変数 a
と b
の型が異なりますが、変数 a
を変数 b
に代入してもエラーは報告されません。この時点では、「b」の型は「a」の型と互換性があると考えられます。
TypeScript では、この状況を表す用語が定義されています。型「A」の値を型「B」に代入できる場合、型「A」は型「B」のサブタイプと呼ばれます。上の例では、タイプ number
はタイプ number|string
のサブタイプです。
TypeScript のルールの 1 つは、親型を使用できる場合はどこでもサブタイプを使用できるが、その逆はできないということです。
let a:'hi' = 'hi';
b:string = 'こんにちは';
b = a; // 正しい
a = b; // エラーレポート
上の例では、「hi」は「string」のサブタイプであり、「string」は「hi」の親タイプです。したがって、変数「a」を変数「b」に代入することはできますが、その一方でエラーが報告されます。
このルールの理由は、サブタイプが親タイプのすべての特性を継承するため、親タイプのコンテキストで使用できるためです。ただし、サブタイプは親タイプにはないいくつかの特性も持つ場合があるため、親タイプをサブタイプのコンテキストで使用することはできません。
作者: wangdoc
アドレス: https://wangdoc.com/
ライセンス: クリエイティブ・コモンズ 3.0