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
}
}
}
CodePudding user response:
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.