I've defined a generics Function, and I'm trying to pass the union of two specific sample of the generics to the function, like
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 };
}
// someother function
myCommonFunc(z);
and it throw errs.
I guess the reason is the function cannot infer type from the unionType, and If so, what should I do?
I know one solution is to use typeguard of z, like
function isTypeA(z: TestX<number> | TestX<string>): z is TestX<number> {
return typeof z.data === 'number';
}
if (isTypeA(z)) {
myCommonFunc(z);
}
but I think it actually change the structure of the program, and it need lots if-else to just for typescript, which is annoying. Can someone give me some other way to solve it?
==========
update:
François's solution is helpful, but somehow it cannot solve the real situation, actually z is a state in React Function Component, and myCommonFunc is a Component, and I'll update the real code:
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]);
// someOther Code
return <MyCommonFunc {...z} />;
};
So I cannot just move the function call to the if-else block. and I'm so sorry that not put the real code at the first time.