Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

TypeScript – Define type alias as subtype of another type alias?

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).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

You can make AnimalPredicates extend Predicates


type Predicate<TValue> = {
    op: "EQUAL" | "NOT_EQUAL",
    value: TValue,
}

type Predicates = Record<string, Predicate<string> | Predicate<boolean>>

/**
 * An implementation of the {@link Predicates} type.
 */
interface AnimalPredicates extends Predicates  {
    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

see TS playground

you can also clean it a bit by restricting the generic itself

type Predicate<TValue extends string | boolean> = {
    op: "EQUAL" | "NOT_EQUAL",
    value: TValue,
}
/**
 * An implementation of the {@link Predicates} type.
 */
interface AnimalPredicates   {
    species: Predicate<string>,
    isMammal: Predicate<boolean>,
}

// EXAMPLE:
const animalPredicates: AnimalPredicates = {
    species: { op: "EQUAL", value: "shiba_inu" },
    isMammal: { op: "EQUAL", value: true },
}

see TS playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading