Typescript type shenanigans 2: specify at least one property
Here is a situation I came across recently - Some part of the system specified a qualified “link” to a page with the following type:
Somewhere else it looked like that:
I wanted some other part to be able to handle both shapes - a use case you’ll come across quite a few times in javascript.
Examples are configuration objects, or intermediate releases to deprecate a previous “shape”, etc. Now, Typescript’s type system’s primary objective seems to be to allow idiomatic javascript to be verified statically, so I googled around to see if somebody figured out a type to express the following:
Given some type with n properties and z optional properties, I want a type that expresses that someone must specifiy at least one of the optional properties
What I found was this wonderful answer at Stackoverflow. The type that does as specified has the following form:
and in the above example you use it as such:
The SO answer in fact fully plays through an example, but before delving in there you should know all of the in-built types and syntax in use.
Exclude
Taken straight from the release notes:
Used on the Keys of a type, it has the following effect:
Pick with Exclude
We also find within the same release notes the following statement
We did not include the
Omit<T, K>
type because it is trivially written asPick<T, Exclude<keyof T, K>>
.
The idea of an Omit
type is to “subtract” the specified properties from some parent type:
Incidentally this is the first part of the RequireOnlyOne
type, giving us the part of the type which we want to be specified in any case.
Advanced types
The following two types are covered in the “Advanced Types” section of the handbook.
The Record-type allows types with n properties where all of the properties are of some specified type. The Partial-type makes all properties of a type optional.
Finally, the feature of mapping types is used, which allows something like projections over types. Here’s a useless but illustrative example:
During the mapping, we can also remove any optionality defined on the property:
I think that this gathers all the interesting in-built pieces used in RequireOnlyOne
that by now you should be able to revisit KPD’s (Who are you?) exquisitely assembled type in the given answer.