1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

エアークローゼットAdvent Calendar 2022

Day 23

TypeScriptのas const

Last updated at Posted at 2022-12-23

TypeScriptのas constの基本的な知識

const x = "hello" as const;

as constconstant 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のプロパティに新たな値をアサインするとコンパイラはエラーを報告します。こんな感じです。

184150153-779c7872-f237-42a4-be52-8ec4bad7a3e0.png

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のコンパイラがエラーを報告します。

こんな感じです。

184151961-108c8d7f-12c8-4a32-b321-5a8dde39dc59.png

user1.detail.name = "New Name"; // detailオブジェクトのプロパティは変更可能ですのでコンパイラエラーが全く出ていません。

でも as constだったら全てプロパティ(親と子ども)が変更不可です。例えば

user2.detail.name = "New Name"; // as constで定義されてるuser2のdetailのnameプロパティを変更すればコンパイラエラーがは発生するはずです。

Screen Shot 2022-12-14 at 17.05.16.png

enumとas constを比較する

パフォーマンス的には同じですが、違うところがあります。下記の各例をみて確認しましょう。

// まずはLinksというenumを定義します
enum Links = {
  Link1 = 'test',
  Link2 = 'test2',
};

↑のようにすれば次のものが受け取れます。

Linksという名前を持ってるValueがもらえる

これはプロパティLink1, Link2と共にランタイムに存在するオブジェクトです。
また、Link1Link2それぞれに対応する値はtest1, test2です。

Linksというタイプ

タイプはコンパイルタイムのみ存在する。↓のように書けば

interface Foo {
  link: Links;
}

linkというプロパティ持ってるFooインターフェースがもらえるし、そのlinkプロパティがLinks.Link1あるいはLinks.Link2を持たないといけません。

LinksというNamespace

LinksというNamespaceからLinks.Link1Links.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.Link1stringをタイプ交換できたいならenumを絶対に避けてください。

TypeScriptのas constについては以上です。

お読みいただきありがとうございます。また次のブログでお会いしましょう。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?