TypeScriptのas constの基本的な知識
const x = "hello" as const;
as const
は constant assertion
- 定数アサーション
とも呼ばれています。as const
を使用すればTypeScriptのコンパイラが次のように認識しています
- xのデータ型は
"hello"
となります (Type "hello"
)かつデータ型が拡張できなくて、例えば"hello"
データ型からstring
に全く変換できません。 - Object literalが
readonly
となります。
別の例
TypeScriptでは下記の宣言を書けば:
const UserType = {
ADMIN: 'ADMIN',
NORMAL: 'NORMAL',
} as const;
UserType
定数のプロパティがreadonly
になります。UserType
のプロパティに新たな値をアサインするとコンパイラはエラーを報告します。こんな感じです。
readonlyとas constの異点
下記のコードを見てみましょう。
type UserDetail = {
name: string;
age: number;
};
type User = {
readonly id: number;
readonly detail: UserDetail;
};
const user1: User = {
id: 1,
detail: {
name: 'User 1 Name',
age: 10,
},
};
const user2 = {
id: 1,
detail: {
name: 'User 2 Name',
age: 20,
},
} as const;
readonly
はプロパティにのみ使用できます。プロパティ値がオブジェクトの場合、そのオブジェクトのプロパティは変更可能です。
user1.detail = {} // こうすればTypeScriptのコンパイラがエラーを報告します。
こんな感じです。
user1.detail.name = "New Name"; // detailオブジェクトのプロパティは変更可能ですのでコンパイラエラーが全く出ていません。
でも as const
だったら全てプロパティ(親と子ども)が変更不可です。例えば
user2.detail.name = "New Name"; // as constで定義されてるuser2のdetailのnameプロパティを変更すればコンパイラエラーがは発生するはずです。
enumとas constを比較する
パフォーマンス的には同じですが、違うところがあります。下記の各例をみて確認しましょう。
// まずはLinksというenumを定義します
enum Links = {
Link1 = 'test',
Link2 = 'test2',
};
↑のようにすれば次のものが受け取れます。
Linksという名前を持ってるValueがもらえる
これはプロパティLink1
, Link2
と共にランタイムに存在するオブジェクトです。
また、Link1
とLink2
それぞれに対応する値はtest1
, test2
です。
Linksというタイプ
タイプはコンパイルタイムのみ存在する。↓のように書けば
interface Foo {
link: Links;
}
link
というプロパティ持ってるFoo
インターフェースがもらえるし、そのlink
プロパティがLinks.Link1
あるいはLinks.Link2
を持たないといけません。
LinksというNamespace
LinksというNamespaceからLinks.Link1
とLinks.Link2
タイプがもらえるから↓のようにも全然書けます。
interface Bar extends Foo {
link: Links.Link1;
}
as const
を使用すると、上記(Value, タイプ, Namespace)を次のように書き換えることができます。
const Links = {
Link1: 'test1',
Link2: 'test2',
} as const;
type Links = (typeof Links)[keyof typeof Links];
namespace Links {
export type Link1 = typeof Links.Link1;
export type Link2 = typeof Links.Link2;
}
さらに
const to: 'test1' = Links.Link1; // いつもOK
const from: Links.Link1 = 'test1';
enumはstring
のnominalサブタイプと見なされます。具体的には
-
string
からLinks.Link1
にキャストできます。 -
Links.Link1
からstring
にキャストできません。
Links.Link1
とstring
をタイプ交換できたいならenum
を絶対に避けてください。
TypeScriptのas const
については以上です。
お読みいただきありがとうございます。また次のブログでお会いしましょう。