Search code examples
typescripttype-inference

How to infer type from property of items of Array-property


I have a type like this:

type Person = {
    name: string;
    relatives: Array<Person>;
    favoriteRelative: string;
}

But I want to enforce favoriteRelative to be a name from any Person in relatives.

I tried this, but got only string instead of the wanted list of strings (probably due to the names not being considered a const-Array):

type Person<R extends Array<Person>> = {
    name: string;
    relatives: R;
    favoriteRelative: R[number]['name'];
}

I tried the infer keyword like this, but got an error :

type Person<T extends Array<Person>> = T extends infer R ? {
    name: string;
    relatives: R;
    favoriteRelative: R[number]['name']; // Type  number  cannot be used to index type  R
} : never

I don't get the answer either out of the Typescript docs or other closely related SO threads.


Solution

  • Dynamic type inference can only be done via functions

    type Person<F extends string = string> = {
        name: string;
        relatives: ReadonlyArray<Person>;
        favoriteRelative: F;
    }
    
    type OneOf<T> = T extends ReadonlyArray<infer E> ? E : never
    type Fallback<T, F> = [T] extends [never] ? F : T
    
    function Person<
      const P extends Person<R>,
      R extends string = Fallback<OneOf<P['relatives']>['name'], string>
    >(person: P): P {
      return person
    }
    

    Typescript playground with examples