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については以上です。
お読みいただきありがとうございます。また次のブログでお会いしましょう。


