1

I dont understand why the code behaves differently when using generics.
The topic is based on the answer for How to create a relation between parameters of a function?

interface Data {
  a: number,
  b: { x: number, y: number}
}

type GetKeyValueTuples<T> = { [Key in keyof T]: [Key, T[Key]] }[keyof T];

function getChangedDataByProperty<T extends Data>(
  ...[data, changedProp, newPropValue]: [T, ...GetKeyValueTuples<T>]
) {
  if (changedProp === "b") {
    changedProp
    return {
      ...data,
      b: {
        // why this has number, a, b types?
        x: newPropValue.x,
        y: newPropValue.y,
      }
    }
  } else {
    return {
      ...data,
      x: newPropValue
    }
  }
}

// why this behaves differently than the abvove function?
function getChangedDataByProperty2(
  ...[data, changedProp, newPropValue]: [Data, ...GetKeyValueTuples<Data>]
) {
  if (changedProp === "b") {
    changedProp
    return {
      ...data,
      b: {
        x: newPropValue.x,
        y: newPropValue.y,
      }
    }
  } else {
    return {
      ...data,
      x: newPropValue
    }
  }
}

The ts playground

0

1 Answer 1

1

The getChangedDataByProperty2() function's rest parameter is of a discriminated union type, and since TypeScript 4.6 we've been able to destructure such discriminated unions into separate parameters to get the narrowing behavior you're seeing, where a check of the discriminant changedProp narrows the type of newPropValue.

On the other hand, getChangedDataByProperty()'s rest parameter is of a generic type which is ultimately constrained to the same discriminated union type. For whatever reason, TypeScript does not consider a generic type to be an acceptable discriminant for a discriminated union. There is an issue filed at microsoft/TypeScript#50652 about this, but it's currently marked as "needs investigation" so there's no official word on whether this is a bug, a design limitation, or can be interpreted as a feature request. It's also on the backlog, which means that such official word might not be forthcoming.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.