Borislav Hadzhiev
Wed Apr 21 2021·2 min read
Photo by Ricardo Rocha
Updated - Wed Apr 21 2021
Lets start with adding props to a component, the simplest way has to do with just adding types to a function, nothing specific to react:
export const Company = () => { return <Employee name="Tim" salary={5000} />; }; type EmployeeProps = { name: string; salary: number; }; const Employee = ({name, salary}: EmployeeProps) => { return ( <div> {name} earns {salary} $. </div> ); };
In the above snippet the Employee
component takes in the name and
salary props, just like you would add types to an object parameter in a
function.
However with the above signature we're not telling typescript that this is a react component. We would want to specifically tell typescript that this is a react component so we get an error if we forget the return statement. The snippet would then look like:
- const Employee = ({name, salary}: EmployeeProps) => { + const Employee: React.FunctionComponent<EmployeeProps> = ({name, salary}) => { return ( <div> {name} earns {salary} $. </div> ); };
The difference being we're now telling typescript that:
propTypes
,
contextTypes
, displayName
etcWhen keeping track of primitive values in state with the useState
hook
typescript can infer the type when you provide an initial value:
import {useState} from 'react'; export const Employee: React.FunctionComponent = () => { const [name, setName] = useState(''); return ( <div> <input value={name} onChange={e => setName(e.target.value)} /> <h3>Employee: {name}</h3> </div> ); };
In the above snippet typescript knows that the name
variable is going to be of
type string, so setting it to any other type would error.
If we however had an array or an object as a state value, providing an empty
array as an initial argument to useState
would initialize the state variable
to never[]
, meaning an array that is always going to be empty, which is not
what we want.
import {useState} from 'react'; export const Employee: React.FunctionComponent = () => { const [name, setName] = useState(''); const [allNames, setAllNames] = useState([]); // <-- allNames are now never[] because typescript can't infer the future value return ( <div> <input value={name} onChange={e => setName(e.target.value)} /> <h3>{allNames}</h3> <button onClick={() => setAllNames(prev => [...prev, name])}> Add name </button> </div> ); };
To help typescript figure out the type of value we intend to store we can pass a
generic to useState
:
export const Employee: React.FunctionComponent = () => { const [name, setName] = useState(''); - const [allNames, setAllNames] = useState([]); + const [allNames, setAllNames] = useState<string[]>([]);
Typescript now knows the type of values the allNames
variable will store, even
though it had no way to infer it initially.