Closed4

[TypeScript] 定数の配列に as const と satisfies をつける

HaruHaru

定数の配列を宣言する

下記のように配列を宣言をすると、stringの配列になる。
要素の取得時にもstringとなってしまい不便。

また配列の更新も可能なため、定数としてよろしくない。

// fruits: string[] に推論される
const fruits = ['apple', 'banana', 'orange'];

// fruit: string | undefined に推論される
const fruit = fruits[0];

// 自由に編集も可能
fruits[10] = 'melon';

const fruit = fruits[0]; がundefinedも考慮するようになるのは、下記tsconfigの noUncheckedIndexedAccess を設定する必要あり。

https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#no-unchecked-indexed-access

HaruHaru

as const のみの場合の問題点

['apple', 'banana', 'orange'] as const
const assertions で厳格になるのは代入後からのため、機能拡張などで ['apple', 'banana', 'orange'] を編集する際に、中身がstringの配列ということを定義したい。

下記では、numberの1を含んだ配列としての定義になってしまう。

// fruits: readonly ["apple", "banana", "orange", 1]
const fruits = ['apple', 'banana', 'orange', 1] as const;

satisfies で定義する

下記のように定義する。
その場合、配列にstring以外を定義した場合はコンパイルエラーとなる。

// コンパイルエラー。numberの1を含んでいるため
const fruits = ['apple', 'banana', 'orange', 1] as const satisfies readonly string[];

// fruits: readonly ["apple", "banana", "orange"]
const fruits = ['apple', 'banana', 'orange'] as const satisfies readonly string[];

The satisfies Operator

https://devblogs.microsoft.com/typescript/announcing-typescript-4-9/#the-satisfies-operator

HaruHaru

上記の例ではわかりやすく配列のみ記述しているが、オブジェクトでも同様の挙動となる。
オブジェクトの方がsatisfiesの恩恵をより受けやすい

// person: {
//    name: string;
//    age: number;
// }
const person = {
  name: '山田太郎',
  age: 20,
};

// const person: {
//    readonly name: "山田太郎";
//    readonly age: 20;
// }
const person = {
  name: '山田太郎',
  age: 20,
} as const;
type Person = {
  name: string;
  age: number;
};

// const person: {
//    readonly name: "山田太郎";
//    readonly age: 20;
// }
const person = {
  name: '山田太郎',
  age: 20,
} as const satisfies Person

// コンパイルエラー
// Personのageの型はnumberであるが、stringで定義しようとしているため
const person = {
  name: '山田太郎',
  age: '20',
} as const satisfies Person
このスクラップは2023/07/25にクローズされました