satisfiesメモ
another way to assign types to values.
値に型を割り当てる方法
まず型割り当ての復習。
値の型をコロンに続けて明示的にアノテーション
const obj: Record<string, string> = {};
obj.id = "123";
値がアノテーションの型そのものであり、その型のみを許容。
let id: string | number = "123";
if (typeof numericId !== "undefined") {
id = numericId;
}
型をユニオンでwidenしてアノテーションもできる。
エッジケースの欠点がある。
When you use a colon, the type BEATS the value.
コロンによる型アノテーションによって、値を型が打ち負かす。
In other words, if you declare a wider type than you want, you're stuck with the wider type.
広めに型定義したら広めな型に留まる
const routes: Record<string, {}> = {
"/": {},
"/users": {},
"/admin/users": {},
};
// No error!
routes.awdkjanwdkjn;
When you use
satisfies
, the value BEATS the type.
satisfies
であれば型を値が打ち負かす
This means it infers the narrowest possible type, not the wider type you specify
可能な限り最も狭い型を推論する
as
による型定義は嘘になり得る
type User = {
id: string;
name: {
first: string;
last: string;
};
};
const user = {} as User;
// No error! But this will break at runtime
user.name.first;
There are some limits to the lies– you can add properties to objects, but you can’t convert between basic types.
ただし基本型の間での嘘はつくことができない。
as
を繰り返したりしない限りは。
const str2 = "my-string" as unknown as number;
There’s one last way to give a type to a variable:
Don’t.
型付けするもう1つの方法は型定義しないこと。推論を効かせる。
- colon annotations
satisfies
as
annotations- not annotating and letting TS infer it
まとめると値に型を指定する方法は、コロンに続けて型指定、satisfies
、as
、型を書かずに推論を効かせる、の4通り
But most of the time, when you want to assign a type to a variable you probably want the type to be wider.
変数に型割り当てるなら、大抵広めに型付けしておきたいかもしれない
The rule of thumb is that you should only use satisfies in two specific situations:
- You want the EXACT type of the variable, not the WIDER type.
- The type is complex enough that you want to make sure you didn’t mess it up
経験則から考えるsatisfies
が必要なケースは2つだけ
- 正確な型が必要なとき
- 何か誤っていないか確認したいほど複雑な型
as const
との組み合わせ
The new
satisfies
operator lets us validate that the type of an expression matches some type, without changing the resulting type of that expression.
式の結果の型を変更することなく、式の型を検証できるもの。
提案のissue
Maybe we don’t care about if the property names match up somehow, but we do care about the types of each property. In that case, we can also ensure that all of an object’s property values conform to some type.
オブジェクトのプロパティ毎に型を検証できる。
as const type assertions can also be used to modify types. But those add readonly to all array and object types, which also might not be what you want
as const
はすべてのobjectとarrayをreadonlyに。
TypeScript's default type inference for objects defaults to inferring primitive values for types, rather than literals.
デフォルトのオブジェクトに対する型推論だと、リテラル型ではなくプリミティブ型
明示的に型アノテーションでも、ユニオンが型狭められてないことで開発者には直観的とはいえない
TypeScript 4.9's new
satisfies
operator introduces a happy compromise between:
annotations and the default type inference.
satisfies
は型推論と明示的な型アノテーションの間を埋めるものになる?
In other words,
satisfies
makes sure a value's type matches some type shape, but doesn't widen the type unnecessarily.
satisfies
はある型の形状にマッチすることを検証できて、不要なwidenをしない。
型アノテーションだとユニオンになるものが、satisfies
だとリテラル型になる
interface Vibe {
mood: "happy" | "sad";
}
const vibe = {
mood: "happy",
} satisfies Vibe;
vibe.mood;
// 型が"happy"になる
it ensures that a type has all the required properties and methods of a specific interface.
特定のインターフェースに必須のプロパティとメソッドを全て持っていることを検証できる。
Having to always validate whether it is a string can be frustrating and cumbersome. This is where the
satisfies
operator comes in.
従来のtsだとunion型で都度値をチェックする処理が必要で面倒だったけど、satisfies
だとそれが解消される
We can also use the
satisfies
operator to tell the TypeScript compiler that it’s OK for an object to include only a subset of the givenkeys
but not accept others.
オブジェクトのキーに制約をかけることができる
Similar to property name constraining, with the exception that in addition to restricting objects to only contain specific properties, we can also ensure that we get all of the
keys
using thesatisfies
operator.
オブジェクトの全てのキーが欠落していないかのチェックもできる
The
satisfies
operator is not only capable of restricting the names of properties in an object, but it can also restrict the values of those properties.
オブジェクトのキーだけではなく値にも制限をかけられる。
When using colon annotation, the type supercedes the value. This means that if you declare a wider type (such as
Record
) and then try to assign and access a narrower value, typescript will not help you.
コロンアノテーションで広めに型定義したら、狭めに値を扱いたいケースでtsの助けはない。
The
satisfies
keyword is a way to say "this value satisfies this type".
satisfies
は、ある値がある型を満たしているという型定義。
This is useful when you want to ensure a value is of the correct type, while keeping it as narrow as possible.
型をなるべく狭めつつ、その型に当てはまる値であることを確かなものとしたいときに便利。
satisfies
should not be your default. It's for handling edge cases
常にsatisfies
を使えば良いということはなく、エッジケースでの利用に留めるもの。
ユースケースとして言及してるのは
https://zenn.dev/link/comments/03a76fe853911e と同じ?
シナリオ
Safe Upcast
The safest workaround is to have a dummy function,
function up<T>(arg: T): T
安全に型をアップキャストするならダミー関数作ることに。
Property Name Constraining
We might want to make a lookup table where the property keys must come from some predefined subset, but not lose type information about what each property's value was:
オブジェクトのプロパティ名に制約をかけつつ各プロパティの型情報を保つ方法がない?
Property Name Fulfillment
Same as Property Name Constraining, except we might want to ensure that we get all of the keys:
すべてのプロパティが欠けてないことを保証する方法がない?
Property Value Conformance
This is the flipside of Property Name Constraining - we might want to make sure that all property values in an object conform to some type, but still keep record of which keys are present:
オブジェクトの各プロパティ値がある型に一致することを確かめたい?
Ensure Interface Implementation
We might want to leverage type inference, but still check that something conforms to an interface and use that interface to provide contextual typing
型推論を活かしつつ、インターフェイスを満たすかチェックしたい?
Optional Member Conformance
オプショナルメンバーの整合性に柔軟性が足りない?
Optional Member Addition
オプショナルメンバーの追加に柔軟性が足りずエラー扱いになる?
Contextual Typing
Type inference also works in “the other direction” in some cases in TypeScript. This is known as “contextual typing”.
このissueで取り上げられているユースケースについてのplayground