I have a generic component with a generic type, which extends required id property GenericComponent = <T extends { id: number }>. Also I have the interface where id is not required:
interface DataInterface {
id?: number;
}
In the <App /> component I render it, checking for existing id, but TS expectedly throws the error:
Type 'DataInterface' does not satisfy the constraint '{ id: number; }'.
Property 'id' is optional in type 'DataInterface' but required in type '{ id: number; }'
I see one way to avoid this: to create a new interface based on my interface and set id as required, like this:
interface DataWithIdInterface extends DataInterface {
id: number
}
But maybe is there any better way?
The example:
interface DataInterface {
id?: number;
}
type Props<T> = {
data: T;
};
const GenericComponent = <T extends { id: number }>({ data }: Props<T>) => (
<div>{data.id}</div>
);
const App = () => {
const data = {
id: undefined
};
if (data.id) {
// error here
return <GenericComponent<DataInterface> data={data} />;
}
return null;
};
CodePudding user response:
There's no way to do what you want.
GenericComponent requires a type that is a subtype of { id: number }. { id?: number } (or { id: number | undefined }) is not compatible with that. In short, GenericComponent assumes that id is always going to be a number - you can't provide it with undefined or no value.
{ id?: number } is a supertype of { id: number }, much like how in classic OOP examples an Animal is a supertype of Cat, and you cannot provide an Animal to an interface that specifically requires a Cat.
The only way to do this is with some kind of wrapper, either like you've written in your example or perhaps by writing a higher-order component. Alternatively, just stick with an if statement - no need to write complicated code when simple code does the job.
CodePudding user response:
I don't know if it's an option, but you could use Required<T>. With it you can "convert" all optional properties of the given type to required. Maybe something like this?
return <GenericComponent<Required<DataInterface>> data={data} />;
