简体   繁体   中英

How can I infer the child property types of an extended Generic type?

I'd like to write a function that returns a property of an extended generic type. Is it even possible?

Here's what I've tried:

interface Animal {
    readonly weight: {total: number}
}

interface Dog extends Animal {
    readonly weight: {total: number, tail: number, head: number, body: number }
}


const getWeight = <T extends Animal>(animal: T) => {
    return animal.weight
}

const myDog = { weight: { total: 20, tail: 5, head: 5, body: 10 } }

const myDogsWeight = getWeight<Dog>(myDog)

// Property 'head' does not exist on type '{ total: number; }'.
const myDogsHeadWeight = myDogsWeight.head



If I try to explicitly annotate the return type of the function, I get another error:

type InferredWeight<TAnimal> = TAnimal extends { readonly weight: infer U } ? U : never
type DogWeight = InferredWeight<Dog> // <-- This type works correctly

const getWeightTyped = <T extends Animal>(animal: T): InferredWeight<T> => {
    // Type '{ total: number; }' is not assignable to type 'InferredWeight<T>'.
    return animal.weight
}



Here's a playground link .

The only TypeScript Github issue that seems relevant is this one , but it is an issue with union types.

As mentioned in the comment by @jcalz you can use a lookup type:

This should do what you are looking for.

interface Animal {
  readonly weight: { total: number }
}

interface Dog extends Animal {
  readonly weight: { total: number, tail: number, head: number, body: number }
}

const getWeight = <
  T extends Animal
>(animal: T): T['weight'] => {
  return animal.weight
}

const myDog = { weight: { total: 20, tail: 5, head: 5, body: 10 } }

const myDogsWeight = getWeight(myDog);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM