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} />;