5

It seems this concept is so basic, there's a lack of documentation about it. I can pass objects as props, but can't seem to pass a basic string literal.

Functional Component

I have a functional component that takes a typed prop, like so:

const ChildComponent = (name: string) => {
    return (
        <div className={styles.childComponent}>
            <p className={styles.styledName}>
                { name }
            </p>
        </div>
    );
}

and call it like so:

<ChildComponent name="testName" />

Error

VSCode throws the error on ChildComponent:

Type '{ name: string; }' is not assignable to type 'string'

I'm very new to Typescript, but from what I can tell, it's reading the string literal as an object.

Possible Solutions

Much of what I've read advises creating a custom typed prop, even for a single property, like so:

Type: NameProp {
name: string
}

and using that as the prop type, instead of string.

Isn't this overkill? Or am I missing something very basic.

5
  • 1
    You have to destructure it from props Commented Aug 14, 2022 at 10:16
  • @DecPK Do you mean: const ChildComponent = ({ name }: string) -> { ... } If so, that just throws the error Property 'name' does not exist on type 'String' Commented Aug 14, 2022 at 10:21
  • @dbcooper I've added my answer please take a look Commented Aug 14, 2022 at 10:22
  • @SergeySosunov declaring the type within curly braces throws the error Binding element 'string' implicitly has an 'any' type. Commented Aug 14, 2022 at 10:24
  • It may look like an overkill, but props in React is always an object, it cannot be a string so you must create that type, otherwise you'll lose typing benefits (like passing a number to a string prop for example) Commented Aug 14, 2022 at 10:34

4 Answers 4

11
const ChildComponent = ({ name }: { name: string }) => {
    return (
        <div className={styles.childComponent}>
            <p className={styles.styledName}>{name}</p>
        </div>
    );
};
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Konrad, for the solution without declaring a custom Type. If possible, could you explain why we need to destructure a primitive string literal? And why the prop must be typed in this fashion instead of ({ name }: string}?
Because string doesn't have property named name. But type { name: string } has property named name. React component requires object as props, never a single value
2

You have to destructure it from props object.

props is an object.

CODESADNBOX LINK

const ChildComponent = (props: ChildComponentProps) => {
    const { name } = props; // CHANGE THAT YOU HAVE TO DO
    return (
        <div className={styles.childComponent}>
            <p className={styles.styledName}>{name}</p>
        </div>
    );
};

or

const ChildComponent = ({ name }: ChildComponentProps) => {
    return (
        <div className={styles.childComponent}>
            <p className={styles.styledName}>{name}</p>
        </div>
    );
};

where ChildComponentProps is

interface ChildComponentProps {
    name: string;
}

1 Comment

Appreciate the quick response! Yes, I'm aware of that solution. But as I mentioned in the OP, I wanted to know if there's a simpler solution. Declaring a custom type ChildComponentProps seems like overkill, especially when it has one (primitive) property. In essence, ChildComponentProps seems to be adding an unnecessary wrapper around string, just so we can destructure it. Is this what Typescript prefers? Or is there a simpler solution?
1

Define a prop interface the define the props parameter as object :

interface Props{
  name:string
}
const ChildComponent: React.FC<Props> = ({name}) => {
    return (
        <div className={styles.childComponent}>
            <p className={styles.styledName}>
                { name }
            </p>
        </div>
    );
}

Comments

0

Props supposed to be an object. You are not the only one using this prop object.

Note that JSX is just a syntax extension use to make it easy to read & code components.

But this code will translate into the pure javascript code,

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

The above code will translate into before execute,

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

Later this createElement will also return an object which will use to build the whole element tree of your application.

// Note: this structure is simplified
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

Notice the children property ? Its also a prop which was not added by you but the React it self.

NOTE: Above code snippets are directly copied from React JS documentation.


So to answer your question,

You cannot change the type of the props object. It must be an object. The reason why you seen that error message is because you forcefully telling the type of props is an string but actually it is not.

The way you should do it is,

const ChildComponent: React.FC<{ name: string }> = ({ name }) => {
    return (
        <div className={styles.childComponent}>
            <p className={styles.styledName}>
                { name }
            </p>
        </div>
    );
}

2 Comments

Thank you @Dilshan for the additional information - very helpful to know how JSX also modifies props. As a side note, is there any reason you prefer the React.FC syntax over the "normal" function expressions? Or is it purely stylistic for you?
Maybe this will help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.