Jewoo Ham
Jewoo Ham

Reputation: 73

How to restrict props.children in react typescript?

import React from 'react';
import './App.css';
import Message from "./components/Message";

function App() {
    return (
        <div className="App">
            <Message>
                <p>Hello World</p>
            </Message>
            <Message>
                <a>Hello World</a>
            </Message>
            <Message>
                <button>Hello World</button>
            </Message>
        </div>
    );
}

export default App;

import React, {FunctionComponent} from 'react';

interface OwnProps {
    children: React.ReactElement<HTMLParagraphElement>;
}

type Props = OwnProps;

const Message: FunctionComponent<Props> = ({children}) => {

    return (
        <h1>
            {children}
        </h1>
    );
};

export default Message;

The above code I can pass any HTMLElementTag as props.
Is there any way to restrict ReactElement to only specific element ? For example only with p tag or button tag etc.

Upvotes: 0

Views: 1808

Answers (3)

Hafid Denguir
Hafid Denguir

Reputation: 952

you can use following for static checking:

type Props = { children: React.ReactNode } //-- allow any React valid Node
// type Props = { children: never } //-- will not allow children to be passed

Upvotes: -1

jkpark
jkpark

Reputation: 323

You can render specific children with React.Children by checking its type. Below example only renders p tag elements.

import React, { Children } from "react";

interface Props {
  children: React.ReactElement<HTMLParagraphElement | HTMLHeadElement>[] | React.ReactElement<HTMLParagraphElement | HTMLHeadElement>;
}

const Component: React.FC<Props> = ({ children }) => {
  const elements = Children.map(children, (child) => {
    if ((child as React.ReactElement).type === "p") {
      return child;
    }
    return null;
    
  })?.filter(Boolean);

  return <div>{elements}</div>;
};

export default Component;

Note that type of custom component is a function, not string. And if you want to check types of nested html elements, you need to recursively check types of react elements children.

I do not know what you are trying to do here, but there may be a better approach than restricting render of children elements.

Upvotes: 2

foakesm
foakesm

Reputation: 933

I think this is the wrong way to be going about implementing HTMl here: if you want a <h1> element to render then you shouldn't be passing <p> or <button> elements into it.

Why not just leave the functional component input here as just a string? Like so:

import React from 'react';

interface MessageProps {
    messageText: string;
}

const Message: React.FC<MessageProps> = ({ messageText }) => {

    return (
        <h1>
            {messageText}
        </h1>
    );
};

export default Message;

//////


import React from 'react';
import Message from "./components/Message";

function App() {
    return (
        <div className="App">
            <Message messageText="Hello world" />
        </div>
    );
}

export default App;


Upvotes: 1

Related Questions