!
)この章では、TypeScriptの型アサーションについて説明します。これは、他の言語の型キャストに関連しており、as
演算子を使用して実行されます。
型アサーションを使用すると、TypeScriptが値に対して計算した静的型をオーバーライドできます。これは、型システムの制限を回避するために役立ちます。
型アサーションは他の言語の型キャストに関連していますが、例外をスローせず、ランタイムでは何も実行しません(静的にいくつかの最小限のチェックを実行します)。
: object = ['a', 'b', 'c']; // (A)
const data
// @ts-expect-error: Property 'length' does not exist on type 'object'.
.length; // (B)
data
.equal(
assertas Array<string>).length, 3); // (C) (data
コメント
A行では、Arrayの型をobject
に広げます。
B行では、この型ではプロパティにアクセスできないことがわかります(詳細)。
C行では、型アサーション(as
演算子)を使用して、data
がArrayであることをTypeScriptに伝えます。これで、.length
プロパティにアクセスできます。
型アサーションは最後の手段であり、できる限り避けるべきです。これにより、静的型システムが通常提供するセーフティネットが(一時的に)削除されます。
A行でも、TypeScriptの静的型をオーバーライドしました。しかし、それは型アノテーションによって行いました。このオーバーライド方法は、型アサーションよりもはるかに安全です。なぜなら、TypeScriptの型はアノテーションの型に代入可能であるという制約がはるかに厳しいためです。
TypeScriptには、型アサーションの代替となる「山括弧」構文があります。
<Array<string>>data
この構文は避けることをお勧めします。それは時代遅れになりつつあり、React JSXコード(.tsx
ファイル内)と互換性がありません。
任意のオブジェクトobj
の.name
プロパティにアクセスするには、obj
の静的型を一時的にNamed
に変更します(A行とB行)。
interface Named {: string;
name
}function getName(obj: object): string {
if (typeof (obj as Named).name === 'string') { // (A)
return (obj as Named).name; // (B)
}'(Unnamed)';
return }
次のコード(A行)では、as Dict
型アサーションを使用することで、推論された型がobject
である値のプロパティにアクセスできます。つまり、静的型object
を静的型Dict
でオーバーライドしています。
= {[k:string]: any};
type Dict
function getPropertyValue(dict: unknown, key: string): any {
if (typeof dict === 'object' && dict !== null && key in dict) {
// %inferred-type: object
;
dict
// @ts-expect-error: Element implicitly has an 'any' type because
// expression of type 'string' can't be used to index type '{}'.
// [...]
;
dict[key]
return (dict as Dict)[key]; // (A)
else {
} throw new Error();
} }
!
)値の型がundefined
またはnull
を含むユニオン型の場合、非ナルアサーション演算子(または非ヌルアサーション演算子)は、これらの型をユニオンから削除します。TypeScriptに「この値はundefined
またはnull
になりません」と伝えています。その結果、これらの2つの値の型によって妨げられていた操作を実行できます。たとえば
= 'Jane' as (null | string);
const theName
// @ts-expect-error: Object is possibly 'null'.
.length;
theName
.equal(
assert!.length, 4); // OK theName
.has()
の後で.get()
Mapメソッド.has()
を使用すると、Mapに特定のキーがあることがわかります。しかし、.get()
の結果はその知識を反映していないため、非ナルアサーション演算子を使用する必要があります。
function getLength(strMap: Map<string, string>, key: string): number {
if (strMap.has(key)) {
// We are sure x is not undefined:
= strMap.get(key)!; // (A)
const value .length;
return value
}-1;
return }
Mapの値がundefined
になることがない場合は、非ナルアサーション演算子を回避できます。その場合、.get()
の結果がundefined
かどうかをチェックすることで、欠損エントリを検出できます。
function getLength(strMap: Map<string, string>, key: string): number {
// %inferred-type: string | undefined
= strMap.get(key);
const value if (value === undefined) { // (A)
-1;
return
}
// %inferred-type: string
;
value
.length;
return value }
厳格なプロパティ初期化がオンになっている場合、TypeScriptが考えていない場合でも、特定のプロパティを初期化していることをTypeScriptに伝える必要がある場合があります。
これは、TypeScriptが不必要にエラーを報告する例です。
class Point1 {// @ts-expect-error: Property 'x' has no initializer and is not definitely
// assigned in the constructor.
: number;
x
// @ts-expect-error: Property 'y' has no initializer and is not definitely
// assigned in the constructor.
: number;
y
constructor() {
.initProperties();
this
}initProperties() {
.x = 0;
this.y = 0;
this
} }
A行とB行で確定代入アサーション(感嘆符)を使用すると、エラーがなくなります。
class Point2 {!: number; // (A)
x!: number; // (B)
yconstructor() {
.initProperties();
this
}initProperties() {
.x = 0;
this.y = 0;
this
} }