Looking for a solution regarding passing the union of two specific samples of generics to a function. The function in question is as follows:
function myCommonFunc<T>({
data,
render,
}: {
data: T;
render: (data: T) => number;
}) {
return render(data);
}
interface TestX<T> {
data: T;
render: (data: T) => number;
}
let z: TestX<number> | TestX<string>;
// let z: TestX<number | string> is wrong, because T will be number | string
if ((window as any).someUserInput === 1) {
z = { data: 1, render: (a: number) => 1 };
} else {
z = { data: '1', render: (a: string) => 1 };
}
// another function
myCommonFunc(z);
Errors are being thrown, possibly because the function cannot infer the type from the union type. What are the possible solutions to tackle this issue?
One solution could be using a type guard for 'z', as demonstrated below:
function isTypeA(z: TestX<number> | TestX<string>): z is TestX<number> {
return typeof z.data === 'number';
}
if (isTypeA(z)) {
myCommonFunc(z);
}
However, this solution might change the program structure significantly and introduce multiple if-else statements just for TypeScript compliance. Is there any other way to address this issue?
==========
Update:
François's solution is informative, but it may not fully resolve the issue. In reality, 'z' represents a state in a React Function Component, and 'myCommonFunc' is a component. The updated code is shown below:
interface TestX<T> {
data: T;
render: (data: T) => number;
}
function MyCommonFunc<T>({ data, render }: TestX<T>) {
return <>{render(data)}</>;
}
type myType = TestX<number> | TestX<string>;
const F = () => {
const [z, setZ] = useState<myType>({ data: 1, render: (a: number) => 1 });
const [userInput, setUserInput] = useState<number>(1);
useEffect(() => {
if (userInput === 1) {
setZ({ data: 1, render: (a: number) => 1 });
} else {
setZ({ data: '1', render: (a: string) => 1 });
}
}, [userInput]);
// additional code
return <MyCommonFunc {...z} />;
};
It is not possible to simply move the function call into the if-else block given the context. Apologies for not providing the actual code initially.