任意の型、不明な型、決して型を入力しない
この章では、TypeScript の型システムを学習するための出発点として使用できる 3 つの特別な型の TypeScript を紹介します。
任意のタイプ
基本的な意味
any 型は制限がないことを意味し、この型の変数には任意の型の値を割り当てることができます。
x:任意にしましょう。
x = 1; // 正しい
x = 'foo'; // 正しい
x = true; // 正しい。
上記の例では、変数 x
の型は any
であるため、任意の型の値を割り当てることができます。
変数の型が「any」に設定されると、TypeScript は実際にこの変数の型チェックをオフにします。明らかな型エラーがあっても、構文が正しい限り、エラーは報告されません。
x:any = 'こんにちは' とします。
x(1) // エラーは報告されませんでした
x.foo = 100; // エラーは報告されませんでした。
上記の例では、変数 x
の値は文字列ですが、それを関数として呼び出したり、プロパティをオブジェクトとして読み取ったりしても、TypeScript はコンパイル時にエラーを報告しません。その理由は、x
の型が any
であり、TypeScript がそれを型チェックしないためです。
このため、「any」型の使用は避けるようにしてください。そうしないと、TypeScript を使用する意味が失われます。
実際の開発では、any 型は主に以下の 2 つの場合に適しています。
(1) 特別な理由により、一部の変数の型チェックをオフにする必要がある場合は、変数の型を「any」に設定できます。
(2) 古い JavaScript プロジェクトに適応し、コードを TypeScript に迅速に移行するために、変数の型を「any」に設定できます。古い一部の大規模な JavaScript プロジェクト、特に他の人のコードでは、各行に正しい型を適用することが困難です。この場合、複合型の変数に「any」を追加しても、TypeScript はコンパイル時にエラーを報告しません。
つまり、TypeScript は、開発者が「any」型を使用している限り、それは開発者が自分でコードを処理したいことを意味すると考えているため、「any」型には制限がなく、任意の方法で使用できます。 。
集合論の観点からは、「any」型は、すべての可能な型を含む他のすべての型の完全な集合とみなすことができます。 TypeScript はこの型を「最上位型」と呼びます。これは、すべての下位層をカバーすることを意味します。
型推論の問題
開発者が型を指定せず、TypeScript が型自体を推論する必要がある変数の場合、型が推論できない場合、TypeScript は変数の型が「any」であると想定します。
関数 add(x, y) {
x + y を返します。
}
add(1, [1, 2, 3]) // エラーは報告されませんでした
上記の例では、関数 add()
のパラメーター変数 x
と y
には十分な情報がありません。TypeScript はそれらの型を推測できず、これら 2 つの変数の型と関数の戻り値を考慮します。値は「任意」です。その結果、関数 add()
は後で型チェックされなくなり、どのような方法でも使用できるようになります。
これは明らかに悪い状況であるため、型が明らかではない変数の場合は、型が「any」として推論されないように、必ず型を明示的に宣言してください。
TypeScript にはコンパイル オプション noImplicitAny
が用意されており、このオプションがオンになっている場合、any
型が推論される限りエラーが報告されます。
$ tsc --noImplicitAny app.ts
上記のコマンドは noImplicitAny
コンパイル オプションを使用してコンパイルされています。この場合、上記の関数 add()
はエラーを報告します。
ここには特殊なケースがあり、「noImplicitAny」がオンになっている場合でも、「let」および「var」コマンドを使用して値を割り当てたり型を指定せずに変数を宣言した場合、エラーは報告されません。
var x; // エラーは報告されませんでした。
let y; // エラーを報告しないでください。
上の例では、変数 x
と y
が値も型も指定せずに宣言されています。TypeScript はそれらの型が any
であると推測します。このとき、noImplicitAny をオンにしてもエラーは報告されません。
x にしましょう。
x = 123;
x = { foo: 'こんにちは' };
上記の例では、変数 x
の型は any
として推論されますが、エラーは報告されず、コンパイルはスムーズに完了します。
このため、「let」と「var」を使用して変数を宣言する場合、値を割り当てない場合は、型を明示的に宣言する必要があります。そうしないと、セキュリティ上のリスクが生じる可能性があります。
const
コマンドにはこの問題はありません。JavaScript 言語では、const
変数を宣言するときに、同時に初期化 (代入) する必要があると規定されているからです。
const x; // エラーレポート
上記の例では、const コマンドで宣言した x の値は変更できません。宣言と同時に値を代入する必要があります。そうしないとエラーが報告されます。 any
としての型推論の問題。
公害問題
型チェックをオフにすることに加えて、「any」型には他の変数を「汚染」するという大きな問題もあります。 (型チェックがないため) 他の型の変数に代入すると、他の変数でエラーが発生する可能性があります。
x:any = 'こんにちは' とします。
y:数値とします。
y = x; // エラーは報告されませんでした。
y * 123 // エラーは報告されませんでした
y.toFixed() // エラーは報告されませんでした
上の例では、変数 x
の型は any
で、実際の値は文字列です。変数 y
の型は number
です。これは、数値変数であることを意味しますが、x
が割り当てられており、エラーは報告されません。その後、変数 y
はさまざまな数値演算を実行し続け、TypeScript はエラーを検出できなくなり、実行時まで問題が残ります。
他の変数を正しい型で汚染し、実行時までエラーが残ることも、「any」型の使用が不適切であるもう 1 つの主な理由です。
不明なタイプ
「任意の」型が他の変数を「汚染」するという問題を解決するために、TypeScript 3.0 では unknown
型 を導入しました。 0.html #new-unknown-top-type)。これは、型が未定義であり、任意の型である可能性があることを示す「any」と同じ意味を持ちます。ただし、その使用にはいくつかの制限があり、「any」ほど自由ではありません。「any」の厳密なバージョンとみなすことができます。 `。
「unknown」は、すべての型の値を「unknown」型に割り当てることができるという点で「any」に似ています。
x:不明にしておきます。
x = true; // 正しい。
x = 42; // 正しい
x = 'Hello World' // 正しい。
上の例では、変数「x」の型は「不明」であり、さまざまな型の値を割り当てることができます。これは「any」の動作と一致します。
「unknown」型と「any」型の違いは、直接使用できないことです。主に以下のような制限があります。
まず第一に、型 unknown
の変数を他の型の変数 (any
型と unknown
型を除く) に直接割り当てることはできません。
v:unknown = 123 とします。
let v1:boolean = v // エラーを報告します。
let v2:number = v; // エラーを報告します。
上の例では、変数 v
の型は unknown
ですが、any
および unknown
以外の型の変数に割り当てられると、エラーが報告されます。これにより、汚染の問題が回避され、 の重大な欠点が克服されます。 「任意」タイプ。
次に、未知の型の変数のメソッドとプロパティを直接呼び出すことはできません。
let v1:unknown = { foo: 123 };
v1.foo // エラーレポート
v2:unknown = 'こんにちは';
v2.trim() // エラーレポート
v3:unknown = (n = 0) => n + 1; とします。
v3() // エラーを報告する
上記の例では、「unknown」型変数のプロパティやメソッドを直接呼び出したり、関数として直接実行したりすると、エラーが報告されます。
第三に、「unknown」型変数が実行できる演算は制限されており、比較演算のみが実行できます (演算子 ==
、===
、!=
、!==
、||
、&&
、?
)、否定演算 (演算子 !
)、typeof
演算子および instanceof
演算子、その他の演算はエラーを報告します。
a:unknown = 1 とします。
a + 1 // エラーを報告する
a === 1 // 正しい
上記の例では、型 unknown
の変数 a
に対して加算演算を実行すると、この演算は許可されていないため、エラーが報告されます。ただし、比較演算は可能です。
では、「unknown」型の変数を使用するにはどうすればよいでしょうか?
答えは、「不明な」型変数は「型削減」後にのみ使用できるということです。いわゆる「型削減」とは、エラーが発生しないように「不明」変数の型範囲を削減することです。
a:unknown = 1 とします。
if (typeof a === '数値') {
r = a + 10 を修正します。
}
上記の例では、「unknown」型の変数「a」に対して「typeof」演算を実行すると、実際の型が「number」であることが判明し、加算演算に使用できます。これは「型削減」であり、未定義の型をより具体的な型に削減します。
別の例を示します。
let s:unknown = 'こんにちは';
if (typeof s === '文字列') {
s.length; // 正しい
}
上の例では、変数 s
の型が文字列であると判定された後でのみ、その length
プロパティを呼び出すことができます。
この設計の目的は、実際の型が明らかな場合にのみ「unknown」変数の使用を許可し、ランダムに使用されて「any」などの他の変数を「汚染」するのを防ぐことです。後でタイプを絞り込んで再度使用しても、エラーは報告されません。
つまり、「unknown」は「any」のより安全なバージョンと考えることができます。一般に、「any」タイプを設定する必要がある場合は、「unknown」タイプに設定することを優先する必要があります。
集合論では、「unknown」は他のすべての型 (「any」を除く) の完全なセットとみなすこともできるため、「any」と同様に、TypeScript のトップレベルの型にも属します。
決して入力しないでください
集合論との対応と型操作の整合性を維持するために、TypeScript では「null 型」の概念も導入しています。つまり、型は空で値が含まれていません。
「null 型」の値が存在しないため、この型は「never」と呼ばれます。つまり、そのような値は存在しません。
x:決してしないでください。
上の例では、変数 x
の型は never
であるため、値を代入することはできません。そうでない場合は、エラーが報告されます。
「never」型の使用シナリオは主に、一部の型操作における型操作の整合性を確保することです。詳細については、次の章を参照してください。さらに、値を返せない関数の場合、戻り値の型を「never」として記述することができます。詳細については「関数」の章を参照してください。
変数に複数の型 (つまり、共用体型) がある場合、通常は分岐を使用して各型を処理する必要があります。このとき、考えられるすべてのタイプを処理した後、残りのケースは「never」タイプに属します。
関数 fn(x:文字列|数値) {
if (typeof x === '文字列') {
// ...
} else if (typeof x === '数値') {
// ...
} それ以外 {
x; // 入力しないでください。
}
}
上記の例では、パラメータ変数 x
は文字列または数値である可能性があり、これら 2 つの状況を判断した後、最後に残った else
分岐では、x
の型は never
になります。
「never」タイプの重要な特徴は、他のタイプに割り当てられることです。
関数 f():never {
throw new Error('Error');
}
let v1:number = f(); // エラーは報告されませんでした。
let v2:string = f(); // エラーは報告されませんでした。
let v3:boolean = f(); // エラーは報告されませんでした
上記の例では、関数 f()
がエラーをスローするため、戻り値の型を never
として記述することができます。これは、値を返すことが不可能であることを意味します。 f()
の結果には、他のさまざまなタイプの変数を割り当てることができます (never
タイプ)。
「never」型を他の型に割り当てることができるのはなぜですか?これは集合論にも関係しており、空集合は任意の集合の部分集合です。したがって、TypeScript では、どの型にも「never」型が含まれると規定しています。したがって、「never」型は他の型と共通であり、TypeScript ではこれを「ボトム型」と呼びます。
つまり、TypeScript には 2 つの「トップレベルの型」(「any」と「unknown」) がありますが、「下位レベルの型」は「never」 1 つだけです。
作者: wangdoc
アドレス: https://wangdoc.com/
ライセンス: クリエイティブ・コモンズ 3.0