🌱

【TypeScript】オブジェクトリテラルの型の拡大を防ぐ

2022/04/11に公開

どうもフロントエンドエンジニアのoreoです。

今回はTypeScriptのconstアサーションについてまとめます。

1 constアサーションとは?

constアサーションを使用することで、主に以下二つのメリットが得られます。

1-1 宣言と同時に型の拡大を制限することができる

具体的には、Widening Literal Typesを制限することができます。Widening Literal Typesとは、以下例のように、constによりname”シンジ”のみを許容するリテラル型ですが、letなど別の変数に代入すると、stringとして型推論されることです。

const name = "シンジ"   //name: "シンジ"

let pilot = name  //pilot: string

1-2 型をreadonlyにできる

型をreadonly(書き換え不可)にできます。

2 使い方

constアサーションを利用するには、オブジェクトリテラルの末尾にas constを記載します。

オブジェクトでの例です。

const profile = {
  name: "シンジ",
  age: 14
} as const;  
//profile: {readonly name: "シンジ"; readonly age: 14;}
 

//readonlyなので、代入できない
profile.name = "アスカ" ;
//Cannot assign to 'name' because it is a read-only property. 

//Widening Literal Typesが制限される
let pilot = profile ;
//pilot: {readonly name: "シンジ"; readonly age: 14;}

配列でも同様です。

const pilots = ["シンジ", "アスカ", "レイ", "マリ"] as const;
//pilots: readonly ["シンジ", "アスカ", "レイ", "マリ"]

//readonlyなので、代入できない
pilots[3] = "トウジ";
//Cannot assign to '3' because it is a read-only property.

//Widening Literal Typesが制限される
let children = pilots;
//children: readonly ["シンジ", "アスカ", "レイ", "マリ"]

オブジェクトリテラルを返す関数で、Widening Literal Typesを制限することもできます

function getPilotOfEVA1() {
  return { pilot: "シンジ" };
}
const pilotOfEVA1 = getPilotOfEVA1();
//pilotOfEVA1: {pilot: string;}

function getPilotOfEVA2() {
  return { pilot: "アスカ" } as const;
}
const pilotOfEVA2 = getPilotOfEVA2();
//pilotOfEVA2: {readonly pilot: "アスカ";}

3 readonlyとの違い

readonlyは、必要なプロパティにのみつけることができますが、constアサーションは全てのプロパティが対象になります。

//readonlyはプロパティ単位で付与可能
type Profile = { readonly name: "シンジ"; age: 14 };

また、constアサーションは、ネストされているオブジェクトでも全てのプロパティをreadonlyにしてくれます。

以下のようにreadonlyをつけたプロパティがオブジェクトである場合、そのオブジェクトのプロパティはreadonlyになりません。EVA2.pilt.name = "シンジ"で代入できてしまいます。

type Pilot = {
  name: string;
  age: number;
};

type EVA = {
  readonly pilt: Pilot;
  readonly color: string;
};

const EVA2: EVA = {
  pilt: {
    name: "アスカ",
    age: 14
  },
  color: "red"
};

//エラーになる
EVA2.color = "blue"
//Cannot assign to 'color' because it is a read-only property

//代入できてしまう
EVA2.pilt.name = "シンジ"

constアサーションを使用すると、ネストされたオブジェクトがもつプロパティもreadonlyになります。

const EVA2 = {
  pilt: {
    name: "アスカ",
    age: 14
  },
  color: "red"
} as const;

//エラーになる
EVA2.color = "blue";
//Cannot assign to 'color' because it is a read-only property.

//エラーになる
EVA2.pilt.name = "シンジ";
//Cannot assign to 'name' because it is a read-only property.

4 最後に

型安全にいきたいですね。

5 参考

constアサーション「as const」 (const assertion) | TypeScript入門『サバイバルTypeScript』

ConditionalTypes I/O - TypeScript3.4 型の強化書 -(電子版) - takepepe - BOOTH

Discussion