type, and may have
resources. For example, we can define a
name: stringand relationships to
relationshipseven when they do not exist. Ideally, we want our generic to be flexible, while being ergonomic to use.
attributesmight not exist, though according to our schema, every
Usershould always have
attributes. As a result, the type system is hindering rather than helping us.
null. However, we now run into another hindrance when trying to create instances of a resource that do not have
relationships: null(which is cumbersome), or by declaring my user as a
Partial<ApiResource<...>>, which loses type information for other properties we want to maintain as non-nullable. We could write a helper type
MarkKeysAsOptional<T>, which isn't a bad solution, but leaves us with two variants of the same type (
UserWithOnlyRequiredProperties), which complicates our type system.
OmitTypes, we can create type constructors that omit keys from interfaces based on the type of their values. We can now write a version of
ApiResourcethat handles both our cases:
Rare not passed, the resultant type will entirely omit the keys
relationships. This is incredibly useful when our resources are modeled as tagged unions, as we never have to null check these properties if our types are properly defined. If we see that
resource.typecorresponds to a resource which has attributes, the type system will know that
resource.attributesALWAYS exists, and we don't have to check it. Conversely, when creating instances of a resource which doesn't have attributes or relationships, we don't have to specify these keys, as the type system knows these will NEVER exist.
nulls are pushed to the absolute boundary of the type, where they do not "infect" our entire union of resources.
OmitTypes. For example, one could collect all event handlers in an interface of React props by filtering out props that aren't functions matching a specific interface. A reverse of
OmitTypescan also be trivially constructed by replacing
Omit. Below are some sample derived types: