Lets say I have a type that looks as follows:
export type IEntity = ({
entity: IReport
setEntity: (report: IReport) => void
} | {
entity: ITest
setEntity: (test: ITest) => void
});
Both entity and setEntity are functions from a zustand store.
My component looks like this:
type IProps = {
values: IValues
meta: IMeta
} & IEntity;
export const CreateField = (props : IProps) => {
...
So when I try to call setEntity inside this component, I get the following error:
Argument of type IReport | ITest is not assignable to parameter of type IReport & ITest
How can I fix this? How do I have to write the correct type definition??
Thanks in advance!
The compiler is unable to handle the "correlated union types" described in ms/TS#30581, however, there is a suggested refactor described in ms/TS#47109, which considers moving to generics. First, we will need some map type that will hold the part of the props that is different:
Now, let's generate the discriminated union, but by using the generics:
We are accepting a generic argument that is constrained to be a key of
TypeMapand by using a mapped type we create an object in the shape oftype: {entity, setEntity}. Then by using the generic argument, we get the desired attribute.Last, but not least is to turn our component into a generic component:
If you hover over
props.setEntityyou will see that it accepts an argument of typeTypeMap[T]and theprops.entityhas exactly that type. In short, we restrict the compiler from narrowing to the exact type which does the trick.playground