Home > Blockchain >  Returning types from mapped types depending on argument
Returning types from mapped types depending on argument

Time:07-14

I'm trying to return the value of a mapped type from a generic function based on an argument, the type seems to be correctly detected on calling but it's reporting error on the return.

I'm not considering using overload on genericFunction as E could have more than 100 values on my use case.

enum E {
  e1="e1",
  e2="e2"
}

interface E1Payload {
  payloadFrom1: string
  anotherField: number
}

interface E2Payload {
  payloadFrom2: string
}

type Mapping = {
  [E.e1]: E1Payload
  [E.e2]: E2Payload
}

function genericFunction<K extends keyof Mapping>(e: K): Mapping[K] {
  if (e === E.e1) {
    // ERROR: Type '{ payloadFrom1: string; anotherField: number; }' is not assignable to type 'Mapping[K]'.
    // Type '{ payloadFrom1: string; anotherField: number; }' is not assignable to type 'E1Payload & E2Payload'.
    // Property 'payloadFrom2' is missing in type '{ payloadFrom1: string; anotherField: number; }' but required in type 'E2Payload'.
    return {
      payloadFrom1: "e1",
      anotherField: 2
    }
  }
  // ERROR: Type '{ payloadFrom2: string; }' is not assignable to type 'Mapping[K]'.
  // Type '{ payloadFrom2: string; }' is not assignable to type 'E1Payload & E2Payload'.
  // Type '{ payloadFrom2: string; }' is missing the following properties from type 'E1Payload': payloadFrom1, anotherField
  return {
    payloadFrom2: "e2"
  }
}

// This work correctly
const payloadE1: E1Payload = genericFunction(E.e1)
const payloadE2: E2Payload = genericFunction(E.e2)

Playground

CodePudding user response:

You can solve this by rewriting genericFunction to contain a map-like structure:

function genericFunction<K extends keyof Mapping>(e: K): Mapping[K] {
  return {
    [E.e1]: {
      payloadFrom1: "e1",
      anotherField: 2
    },
    [E.e2]: {
      payloadFrom2: "e2"
    }
  }[e]
}

For more complex scenarios, I would advise using a type assertion. TypeScript can not really narrow down generic types. That's why it can not understand the if/else narrowing you are doing here.

Playground

  • Related