メインコンテンツまでスキップ

satisfies演算子「satisfies operator」

satisfies T(Tは型)は、変数宣言時に使用する演算子で、その値が型Tを満たすことを検証します。この演算子は型の絞り込みを保持したまま型チェックを行える特徴があります。

as constと異なり、satisfiesはその後に型を要求します。単独で使用することはできません。

型アノテーションと同じようにできること

変数宣言のときに変数名の後ろに: Tと書くことを型アノテーションといいます。こちらは変数宣言時にその変数が型Tを満たすことを検証します。

というとsatisfies Tの機能が型アノテーションとまったく同じように見えます。実際次の例はまったく同じ働きをします。

ts
type Pokemon = {
name: string;
no: number;
genre: string;
height: number;
weight: number;
};
const pikachu: Pokemon = {
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
};
const raichu = {
name: "raichu",
no: 26,
genre: "mouse pokémon",
height: 0.8,
weight: 30.0,
} satisfies Pokemon;
ts
type Pokemon = {
name: string;
no: number;
genre: string;
height: number;
weight: number;
};
const pikachu: Pokemon = {
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
};
const raichu = {
name: "raichu",
no: 26,
genre: "mouse pokémon",
height: 0.8,
weight: 30.0,
} satisfies Pokemon;

どちらも宣言した型に沿わない型を与えるとエラーが発生します。
また、存在しないプロパティを追加することもできません。

ts
const pikachu: Pokemon = {
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: "0.4m",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
weight: "6.0kg",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
};
const raichu = {
name: "raichu",
no: 26,
genre: "mouse pokémon",
height: "0.8m",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
weight: "30.0kg",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
} satisfies Pokemon;
ts
const pikachu: Pokemon = {
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: "0.4m",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
weight: "6.0kg",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
};
const raichu = {
name: "raichu",
no: 26,
genre: "mouse pokémon",
height: "0.8m",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
weight: "30.0kg",
Type 'string' is not assignable to type 'number'.2322Type 'string' is not assignable to type 'number'.
} satisfies Pokemon;
ts
const pikachu: Pokemon = {
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
type: "electric",
Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.2353Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.
};
const raichu = {
name: "raichu",
no: 26,
genre: "mouse pokémon",
height: 0.8,
weight: 30.0,
type: "electric",
Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.2353Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.
} satisfies Pokemon;
ts
const pikachu: Pokemon = {
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
type: "electric",
Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.2353Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.
};
const raichu = {
name: "raichu",
no: 26,
genre: "mouse pokémon",
height: 0.8,
weight: 30.0,
type: "electric",
Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.2353Object literal may only specify known properties, and 'type' does not exist in type 'Pokemon'.
} satisfies Pokemon;

型アノテーションとちがうこと

satisfiesの最大の特徴は、型Tにユニオン型が含まれる場合でも、実際の値に基づいて型を絞り込むことができる点です。型アノテーションでは失われてしまう型の情報を保持できます。
主にオブジェクトリテラルや配列で使用しますが、プリミティブ型でも使用できます。

ts
const array1: (string | number)[] = [1, 2, 3];
const array1: (string | number)[]
const array2 = [1, 2, 3] satisfies (string | number)[];
const array2: number[]
ts
const array1: (string | number)[] = [1, 2, 3];
const array1: (string | number)[]
const array2 = [1, 2, 3] satisfies (string | number)[];
const array2: number[]

ユニオン型の配列の場合は期待する結果にならないときもあります。

ts
const array1: (string | number)[] = [1, "2", 3];
const array1: (string | number)[]
const array2 = [1, "2", 3] satisfies (string | number)[];
const array2: (string | number)[]
ts
const array1: (string | number)[] = [1, "2", 3];
const array1: (string | number)[]
const array2 = [1, "2", 3] satisfies (string | number)[];
const array2: (string | number)[]

タプル型の場合は個々に型の絞り込みを行います。

ts
const tuple1: [string | number, string | number, string | number] = [1, "2", 3];
const tuple2 = [1, "2", 3] satisfies [
const tuple1: [string | number, string | number, string | number]
string | number,
const tuple2: [number, string, number]
string | number,
string | number
];
ts
const tuple1: [string | number, string | number, string | number] = [1, "2", 3];
const tuple2 = [1, "2", 3] satisfies [
const tuple1: [string | number, string | number, string | number]
string | number,
const tuple2: [number, string, number]
string | number,
string | number
];

オブジェクトのプロパティにあるユニオン型にも効果があります。

ts
type SuccessResponse = {
success: true;
data: object;
};
type ErrorResponse = {
success: false;
error: string;
};
type ApiResponse = SuccessResponse | ErrorResponse;
 
const res1: ApiResponse = {
success: false,
const res1: ApiResponse
error: "too many requests",
};
const res2 = {
success: false,
const res2: { success: false; error: string; }
error: "too many requests",
} satisfies ApiResponse;
ts
type SuccessResponse = {
success: true;
data: object;
};
type ErrorResponse = {
success: false;
error: string;
};
type ApiResponse = SuccessResponse | ErrorResponse;
 
const res1: ApiResponse = {
success: false,
const res1: ApiResponse
error: "too many requests",
};
const res2 = {
success: false,
const res2: { success: false; error: string; }
error: "too many requests",
} satisfies ApiResponse;

as constと組み合わせる

as constと組み合わせてas const satisfies Tと書くことができます。

これは型Tを満たしていることを検証した上で絞り込みを行い、さらにリテラル型にしてreadonlyにするというas constsatisfiesの機能をあわせ持っています。

ts
const array = [1, "2", 3] as const satisfies (string | number)[];
const tuple = [1, "2", 3] as const satisfies [
const array: [1, "2", 3]
string | number,
const tuple: [1, "2", 3]
string | number,
string | number
];
 
const res = {
success: false,
const res: { readonly success: false; readonly error: "too many requests"; }
error: "too many requests",
} as const satisfies ApiResponse;
ts
const array = [1, "2", 3] as const satisfies (string | number)[];
const tuple = [1, "2", 3] as const satisfies [
const array: [1, "2", 3]
string | number,
const tuple: [1, "2", 3]
string | number,
string | number
];
 
const res = {
success: false,
const res: { readonly success: false; readonly error: "too many requests"; }
error: "too many requests",
} as const satisfies ApiResponse;