Reputation: 628
For example component looks like this:
interface TData {
name: string;
id: number;
}
interface TComponent {
data: TData[]
}
const Component = (props: TComponent) => { // JSX }
But i want to pass array that has data with additional field(for example slug
doesnt matter)
Which does not match interface but has required fields. I want component accept everything that has name, id
and whatever additional fields are. How do i achieve this?
Upvotes: 0
Views: 643
Reputation: 11581
TypeScript is already a "structural type system" which means types are broadly "compatible" as long as the "required" matching properties exist on the object.
The basic rule for TypeScript’s structural type system is that x is compatible with y if y has at least the same members as x.
So in theory what you are already doing should be fine. So why are you getting an error?
The reason is that when you assign a literal object value directly to a variable or parameter that has a defined type, "excess property checking" will kick in, enforcing that the object does not have properties in beyond what has been defined explicitly.
Again, the docs (I don't know why this page is deprecated, there is no equivalent to this I can find in the new version of the docs, however this is still relevant):
Object literals get special treatment and undergo excess property checking when assigning them to other variables, or passing them as arguments. If an object literal has any properties that the “target type” doesn’t have, you’ll get an error
TypeScript assumes that if you're doing this, it's a bug and you should fix it, hence the error. And for what it's worth, I agree. It is bad practice to define types with the expectation that they will have extra properties, unused by the function or component they are passed to. I guarantee there are better, type-safe ways to structure your types (see: Generics)
But, if you absolutely insist on working around these errors rather than reconsidering your type structures, you can easily do so just by avoiding passing in literal values to your components. For example, the following gives an error because the property other
does not exist on TData
:
<Component data={[{name: '', id: 0, other: ''}]} />
However, by aliasing our data values through an untyped/inferred variable declaration, we are technically no longer passing a literal value to the component, we are passing a variable with an inferred type, bypassing TypeScript's excess property checking:
const data = [{name: '', id: 0, other: ''}];
return <Component data={data} />
Keep in mind that you have to leverage TypeScript's inference engine here. You will run into the same error if you start trying to explicitly type the variables that you're assigning object literals with excess properties. For example, this will also give an error:
const data: TData = [{name: '', id: 0, other: ''}];
return <Component data={data} />
Upvotes: 3