Jordan
Jordan

Reputation: 1121

Nesting a TypeScript React component inside another

So I'm trying to nest a TypeScript React component within another, but it complains about types. It would seem it wants me to add all of my props into the parent interface?

Is there a way of doing this without having to have all my types listed in the child component interface, but then also having to add the types to the parent component interface?

Note: I am using Styled Components in the example below

interface IField {
  children: React.ReactNode
}

export function Field({ children, htmlFor, label, required, ...props }: IField) {
  return (
    <FormField {...props}>
      <Label htmlFor={htmlFor} label={label} required={required}/>
      {children}
    </FormField>
  )
}

interface ILabel {
  htmlFor: string
  label: string
  required?: boolean
}

export function Label({ htmlFor, label, required }: ILabel) {
  return (
    <FormLabel htmlFor={htmlFor}>
      {label}
      {required && (
        <Required />
      )}
    </FormLabel>
  )
}

Error I get:

Type '{}' is missing the following properties from type 'ILabel': htmlFor, label

Thanks for any help in advance!

Upvotes: 1

Views: 5186

Answers (1)

j3ff
j3ff

Reputation: 6089

To avoid adding the properties from the child interface back to the parent component interface you can use extends (see TypeScript inheritance documentation).

After that, you can pass the props from the parent to the child component by using {...props} deconstructor on the child component.

And finally, if you are using TypeScript might as well use React.FunctionComponent typing to avoid having to manually type children.

You can check at this simplified working example:
https://stackblitz.com/edit/react-stackoverflow-60228406

I tried to adapt your snippet below...

import React from 'react';

interface IField extends ILabel {
}

export const Field: React.FunctionComponent<IField> = (props) => {
  return (
    <FormField>
      <Label {...props} />
      {props.children}
    </FormField>
  )
};

interface ILabel {
  htmlFor: string
  label: string
  required?: boolean
}

export const Label: React.FunctionComponent<ILabel> = (props) => {
  return (
    <FormLabel htmlFor={props.htmlFor}>
      {props.label}
      {props.required && (<Required />)}
    </FormLabel>
  )
};

Upvotes: 1

Related Questions