Reputation: 2136
I have an onClick
event in one of my functional components:
import * as React from 'react';
const BreadCrumbs: React.SFC<{level: Array<string>, changeLevel: Function}> = ({level, changeLevel}) => {
return (
<div>
{
level.map(function(elem, i) {
return <span key={i} onClick={changeLevel}>{elem}</span>
})
}
</div>
)
}
export default BreadCrumbs;
In the parent component I supply the <BreadCrumbs>
component with props of an array and a function reference:
<BreadCrumbs level={this.state.levels} changeLevel={this.changeLevel}/>
This doesn't work because in the <BreadCrumbs>
component, the Typescript compiler fails with the error (on return <span>
line):
[ts]
Type '{ key: number; onClick: Function; children: string; }' is not assignable to type 'DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>'.
Type '{ key: number; onClick: Function; children: string; }' is not assignable to type 'HTMLAttributes<HTMLSpanElement>'.
Types of property 'onClick' are incompatible.
Type 'Function' is not assignable to type '((event: MouseEvent<HTMLSpanElement>) => void) | undefined'.
Type 'Function' is not assignable to type '(event: MouseEvent<HTMLSpanElement>) => void'.
Type 'Function' provides no match for the signature '(event: MouseEvent<HTMLSpanElement>): void'.
(JSX attribute) onClick: Function
However, if I modify my code to this:
const BreadCrumbs: React.SFC<{level: Array<string>, changeLevel: Function}> = ({level, changeLevel}) => {
function something(i: number) {
changeLevel(i);
}
return (
<div>
{
level.map(function(elem, i) {
return <span key={i} onClick={something.bind(this, i)}>{elem}</span>
})
}
</div>
)
}
export default BreadCrumbs;
Everything works fine. Why doesn't the first version work?
Upvotes: 0
Views: 1611
Reputation: 311
In TypeScript, it use a strongly typed manner to perform type checking on functions, which takes the parameters and returned value of a function into consideration. Thus, for the parameter (React component prop) changeLevel
, its type should be declared as (event: React.MouseEvent<HTMLSpanElement>) => void
or compatible types (like (e: React.MouseEvent<Element>) => void
, () => void
, or () => any
). The Function
type is not used for function type declaration, but for typing the global constructor of any function object, which lacks the information about function object and should be avoided when typing a function.
You can change your code to following version to pass TypeScript's checking.
const BreadCrumbs: React.SFC<{level: Array<string>, changeLevel: () => void}> = ({level, changeLevel}) => {
return (
<div>
{
level.map(function(elem, i) {
return <span key={i} onClick={changeLevel}>{elem}</span>
})
}
</div>
)
}
Actually, in the second version, the return type of bind
function is any
, which can be assigned to variable of any type in TypeScript. TypeScript performs no type checking in that version.
Upvotes: 1