In TypeScript, is it possible for a type alias to "implement" (or become subtype of) another type alias?
For example, I have the following type aliases (TS Playground Link):
type Predicate<TValue> = {
op: "EQUAL" | "NOT_EQUAL",
value: TValue,
}
type Predicates = Record<string, Predicate<string> | Predicate<boolean>>
/**
* An implementation of the {@link Predicates} type.
*/
type AnimalPredicates = {
species: Predicate<string>,
isMammal: Predicate<boolean>,
}
// EXAMPLE:
const animalPredicates: AnimalPredicates = {
species: { op: "EQUAL", value: "shiba_inu" },
isMammal: { op: "EQUAL", value: true },
}
// `AnimalPredicates` is a subtype of `Predicates` so this is allowed
const animalPredicates2: Predicates = animalPredicates
The AnimalPredicates
type alias is an implementation of the Predicates
type (i.e. AnimalPredicates
is subtype of Predicates
).
Although I added a JSDoc comment saying that AnimalPredicates
implements Predicates
, it does not prevent me from doing something like:
type AnimalPredicates = {
// Predicate<number> is NOT allowed as record value in `Predicates`
// But TS compiler does not complain...
species: Predicate<number>,
}
Is there a workaround to let the TS compiler know that AnimalPredicates
must be a subtype of the Predicate
type?
If you are looking for the type-level satisfies
, it looks like this:
type Satisfies<I, T extends I> = T
type Predicates = Record<string, Predicate<string> | Predicate<boolean>>
type AnimalPredicates = Satisfies<Predicates, {
species: Predicate<string>,
isMammal: Predicate<boolean>,
}>
type NotPredicates = Satisfies<Predicates, {
species: Predicate<string>,
isMammal: string,
// Type '{ species: Predicate<string>; isMammal: string; }' does not satisfy the constraint 'Predicates'.
// Property 'isMammal' is incompatible with index signature.
// Type 'string' is not assignable to type 'Predicate<string> | Predicate<boolean>'.(2344)
}>