Setup
Our browser quickstart already sets you up to develop react applications. Here are the key highlights.
- Use files with the extension
.tsx
(instead of.ts
). - Use
"jsx" : "react"
in yourtsconfig.json
‘scompilerOptions
. - Install the definitions for JSX and React into your project : (
npm i -D @types/react @types/react-dom
). - Import react into your
.tsx
files (import * as React from "react"
).
HTML Tags vs. Components
React can either render HTML tags (strings) or React components (classes). The JavaScript emit for these elements is different (React.createElement('div')
vs. React.createElement(MyComponent)
). The way this is determined is by the case of the first letter. foo
is treated as an HTML tag and Foo
is treated as a component.
Type Checking
HTML Tags
An HTML Tag foo
is to be of the type JSX.IntrinsicElements.foo
. These types are already defined for all the major tags in a file react-jsx.d.ts
which we had you install as a part of the setup. Here is a sample of the the contents of the file:
declare module JSX {
interface IntrinsicElements {
a: React.HTMLAttributes;
abbr: React.HTMLAttributes;
div: React.HTMLAttributes;
span: React.HTMLAttributes;
/// so on ...
}
}
Stateless Functional Components
You can define stateless components simply with the React.SFC
interface e.g.
type Props = {
foo: string;
}
const MyComponent: React.SFC<Props> = (props) => {
return <span>{props.foo}</span>
}
<MyComponent foo="bar" />
Stateful Components
Components are type checked based on the props
property of the component. This is modeled after how JSX is transformed i.e. the attributes become the props
of the component.
To create React Stateful components you use ES6 classes. The react.d.ts
file defines the React.Component<Props,State>
class which you should extend in your own class providing your own Props
and State
interfaces. This is demonstrated below:
type Props = {
foo: string;
}
class MyComponent extends React.Component<Props, {}> {
render() {
return <span>{this.props.foo}</span>
}
}
<MyComponent foo="bar" />
React JSX Tip: Interface for renderable
React can render a few things like JSX
or string
. There are all consolidated into the type React.ReactNode
so use it for when you want to accept renderables e.g.
type Props = {
header: React.ReactNode;
body: React.ReactNode;
}
class MyComponent extends React.Component<Props, {}> {
render() {
return <div>
{this.props.header}
{this.props.body}
</div>;
}
}
<MyComponent foo="bar" />
React JSX Tip: Accept an instance of a Component
The react type definitions provide React.ReactElement<T>
to allow you to annotate the result of a <T/>
class component instantiation. e.g.
class MyAwesomeComponent extends React.Component {
render() {
return <div>Hello</div>;
}
}
const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error!
Of course you can use this as a function argument annotation and even React component prop member.
React JSX Tip: Generic components
It works exactly as expected. Here is an example:
/** A generic component */
type SelectProps<T> = { items: T[] }
class Select<T> extends React.Component<SelectProps<T>, any> { }
/** Usage */
const Form = () => <Select<string> items={['a','b']} />;
Generic functions
Something like the following works fine:
function foo<T>(x: T): T { return x; }
However using an arrow generic function will not:
const foo = <T>(x: T) => x; // ERROR : unclosed `T` tag
Workaround: Use extends
on the generic parameter to hint the compiler that it’s a generic, e.g.:
const foo = <T extends {}>(x: T) => x;
Type Assertions
Use as Foo
syntax for type assertions as we mentioned before.
Default Props
- Stateful components with default props: You can tell TypeScript that a property will be provided externally (by React) by using a null assertion operator (this isn’t ideal but is the simplest minimum extra code solution I could think of).
class Hello extends React.Component<{
/**
* @default 'TypeScript'
*/
compiler?: string,
framework: string
}> {
static defaultProps = {
compiler: 'TypeScript'
}
render() {
const compiler = this.props.compiler!;
return (
<div>
<div>{compiler}</div>
<div>{this.props.framework}</div>
</div>
);
}
}
ReactDOM.render(
<Hello framework="React" />, // TypeScript React
document.getElementById("root")
);
- SFC with default props: Recommend leveraging simple JavaScript patterns as they work well with TypeScript’s type system e.g.
const Hello: React.SFC<{
/**
* @default 'TypeScript'
*/
compiler?: string,
framework: string
}> = ({
compiler = 'TypeScript', // Default prop
framework
}) => {
return (
<div>
<div>{compiler}</div>
<div>{framework}</div>
</div>
);
};
ReactDOM.render(
<Hello framework="React" />, // TypeScript React
document.getElementById("root")
);