【TypeScript】変数宣言constとas constの違い
更新日:2022/11/09
TypeScriptには as constというアサーションがあります。
一方、JavaScriptは変数宣言でconstを使用します。
それぞれのTypeScriptにおける違いと、使い方についてお伝えします。
変数宣言const
まずは変数宣言のconstから見ていきます。
JavaScriptのconst
変数を宣言するconstは、JavaScriptの構文です。
constで宣言された変数は、値を変更できません。
変更しようとすると、実行時にエラーになります。
const a = 1000;
a = 1; // エラー: TypeError: Assignment to constant variable.
オブジェクトは、少し注意が必要です。
constで宣言した場合でも、プロパティ値を変更できます。
const a = {value:1000};
a.value = 1;
しかし、変数そのものへの代入はエラーになります。
a = {text:"abc"}; // エラー: TypeError: Assignment to constant variable.
理由等については、次のページを読んでみてください。
TypeScriptのconst
TypeScriptのconstは、JavaScriptの動作を踏まえて、変数に型付けされます。
プリミティブ
プリミティブを持つconst変数は、定数とみなせます。
そのため、リテラル型として型付けされます。
const a=5; // const a: 5
const b="abc"; // const b: "abc"
const c = a; // const c: 5
異なる値を代入すると、TypeScriptがエラー出力します。
c = 100; // エラー: Cannot assign to 'c' because it is a constant.
これは、リテラル型と異なる値を代入したことによるエラーではなくて、const変数に代入したことによるエラーです。
オブジェクト
オブジェクトを持つconst変数は、各プロパティを関連する型に型付けします。
const a={ // const a:{ val: number; txt: string; }
val:100,
txt:"abc"
};
プロパティ値の変更はできます。
しかし、新しいプロパティの追加はできません。
a.val = 200;
a.val2 = 300; // エラー: Property 'val2' does not exist on type '{ val: number; txt: string; }'. Did you mean 'val'?
変数そのものへの代入は、プリミティブでのケースと同様に、エラー出力されます。
a = 100; // エラー: Cannot assign to 'a' because it is a constant.
as const
TypeScriptの as const は、リテラル値またはenum型のメンバーの型を、リテラル型に強制します。
リテラル型とは、1や2などの数値や"hello","こんにちは"などのテキストなど、値そのものを型としたもので、その値のみを保持できます。
■例
const value:"hello" = "hello"
対象がプリミティブのケース
letやvarで宣言した変数は、通常は値の型で型付けされます。
let a = 100; // a: number
let b = "abc"; // b: string
as constを使用すると、リテラル型になります。
let a = 100 as const; // a: 100
let b = "abc" as const; // b: "abc"
リテラル型で型付けされているので、他の値を代入するとエラーになります。
a = 1000; // Type '1000' is not assignable to type '100'.
ちなみに、letではなくてconstで変数宣言した場合は、const変数に代入したという理由でエラーになります。
let a = 100 as const;
a = 1000; // Cannot assign to 'a' because it is a constant.
なお、as constはenum型を除いて、リテラルのみで使用できます。
変数で使用すると、エラーです。
let a = 100;
let b = a as const; // エラー: A 'const' assertions can only be applied to references to enum members, or string, number, boolean, array, or object literals.
対象がオブジェクトのケース
オブジェクトは、通常は各プロパティをプロパティ値の型で型付けします。
let a ={ // a: { val: number; text: string; }
val:100,
text:"abc"
};
as constを使用すると、プロパティの型はreadonlyのリテラル型になります。
let a ={ // { readonly val: 100; readonly text: "abc"; }
val:100,
text:"abc"
} as const;
オブジェクト内にオブジェクトがある場合、内部のオブジェクトも同様に型付けされます。
let a ={ // a: {
// readonly val: 100;
// readonly text: "abc";
// readonly obj: {
// readonly val2: 200;
// readonly text2: "cde";
// };
// }
val:100,
text:"abc",
obj:{
val2:200,
text2:"cde"
}
} as const;
なおオブジェクトも、as constを使用できるのはリテラルのみです。
変数で使用すると、エラーです。
対象がenum型のケース
enum型はメンバーに対してのみ as constを使用できます。
enum型そのものに使うと、エラーです。
enum aaa{
a1,a2,a3
}
let b1 = aaa.a1; // b1: aaa
let b2 = aaa.a1 as const; // b2: aaa.a1
let b3 = aaa as const; // エラー: A 'const' assertions can only be applied to references to enum members, or string, number, boolean, array, or object literals.
as constの置き換え
as constは基本的には、次のように型アノテーションに置き換えることができます。
プリミティブ値の置き換え
let value = 100 as const;
↓
let value:100 = 100;
実際には、定数としての使用を目的とすることが多いので const value = 100; と記述すべきですね。
配列(タプル型)の置き換え
let array = ["a",100,true] as const;
↓
let array:readonly["a",100,true] = ["a",100,true];
オブジェクトの置き換え
let c = { a:"ab",c:"de"} as const;
↓
let c:{
readonly a:"ab",
readonly c:"de",
} = { a:"ab",c:"de"};
配列とオブジェクトは、as constの方がスッキリしますね。
オブジェクトに関しては下位の階層にもas constを適用します。
状況にとっては下位に適用して欲しくないケースもあるので、ケースバイケースで使い分ける必要があります。
as constの使用例
as constの使用例として、次のようなオブジェクトのプロパティ値をunion型に変換するコードが挙げられることが多いです。
const obj ={
a:"abc",
b:"cde",
c:"efg"
} as const;
type ObjValues = typeof obj[ keyof typeof obj ]; // "abc" | "cde" | "efg"
取得したunion型の使い道はあまり多くないというか思いつきません…
更新日:2022/11/09
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。