React function components take a single props parameter. If you mistakenly think they take positional parameters, the error message you get can be quite confusing because it says nothing about the number of parameters. Instead, it's usually something to do with assignability.
Even if this is WAI, maybe this helps someone else with this error!
TypeScript Version: 3.5.2
Search Terms:
- react function component error message
Code
import * as React from 'react';
function FC(a: any, b: number, c: number) {
return <div>{a} {b} {c}</div>;
}
function MainComponent() {
return <FC a="A" b="B" c="C" />
}
Expected behavior:
It should be an error to use a function which takes multiple parameters as a component in JSX. This is almost certainly a mistake. It's similar to calling a two-parameter function with one parameter, which is an error:
FC({a: 'A', b: 'B', c: 'C'});
// Expected 3 arguments, but got 1. ts(2554)
Actual behavior:
No error. b and c are undefined at runtime.
Playground Link: link
Related Issues:
Real-world example of the confusing way in which this came up:
import * as React from 'react';
interface RowType {
[columnName: string]: string | number;
}
function CardComponent(props: {row: RowType; column: string; tooltip: string}): JSX.Element {
return <div title={props.tooltip}>{props.row[props.column] || ''}</div>;
}
export class MyComponent extends React.Component<{row: RowType}, {}> {
render() {
const createCard = (col: string) => (
<CardComponent
row={this.props.row}
key={col}
column={col}
tooltip={`This is column ${col}`}
/>
);
const els = ['A', 'B', 'C'].map((v, i) => createCard(v));
return <div>{els}</div>;
}
}
Refactor createCard to be a function component:
const FunctionCard = (row: RowType, column: string) => (
<CardComponent row={row} column={column} tooltip={`This is column ${column}`} />
);
class MyComponent2 extends React.Component<{row: RowType}, {}> {
render() {
const createCard = (col: string) => (
<FunctionCard row={this.props.row} key={col} column={col} />
);
const els = ['A', 'B', 'C'].map((v, i) => createCard(v));
return <div>{els}</div>;
}
}
You get the following error message on the row=:
Type 'RowType' is not assignable to type 'string | number'.
Type 'RowType' is not assignable to type 'string'.ts(2322)
Toy.tsx(6, 3): The expected type comes from this index signature.
It's not clear at first glance why the type checker is trying to assign RowType to string | number. If you squint hard enough, you eventually realize that FunctionCard is getting called with a single argument:
FunctionCard({
row: this.props.row,
column: col
})
TypeScript tries to assign this {row, column} object to the first parameter of FunctionCard, namely row. Since this is RowType, which has an index signature, it tries to assign this.props.row (whose type is RowType) to the value type of the index signature, namely string | number. Hence the error.
React function components take a single
propsparameter. If you mistakenly think they take positional parameters, the error message you get can be quite confusing because it says nothing about the number of parameters. Instead, it's usually something to do with assignability.Even if this is WAI, maybe this helps someone else with this error!
TypeScript Version: 3.5.2
Search Terms:
Code
Expected behavior:
It should be an error to use a function which takes multiple parameters as a component in JSX. This is almost certainly a mistake. It's similar to calling a two-parameter function with one parameter, which is an error:
Actual behavior:
No error.
bandcareundefinedat runtime.Playground Link: link
Related Issues:
Real-world example of the confusing way in which this came up:
Refactor
createCardto be a function component:You get the following error message on the
row=:It's not clear at first glance why the type checker is trying to assign
RowTypetostring | number. If you squint hard enough, you eventually realize thatFunctionCardis getting called with a single argument:TypeScript tries to assign this
{row, column}object to the first parameter ofFunctionCard, namelyrow. Since this isRowType, which has an index signature, it tries to assignthis.props.row(whose type isRowType) to the value type of the index signature, namelystring | number. Hence the error.