Skip to content

Commit 72b489d

Browse files
committed
Redirect to the official TS website
1 parent 830a6f2 commit 72b489d

File tree

1 file changed

+1
-289
lines changed

1 file changed

+1
-289
lines changed

JSX.md

+1-289
Original file line numberDiff line numberDiff line change
@@ -1,289 +1 @@
1-
# Introduction
2-
3-
JSX is an embeddable XML-like syntax.
4-
It is meant to be transformed into valid JavaScript but the semantics of that transformation are implementation-specific.
5-
JSX came to popularity with the React library but has since seen other applications.
6-
TypeScript supports embedding, type checking, and optionally compiling JSX directly into JavaScript.
7-
8-
# Basic usage
9-
10-
In order to use JSX you must do two things.
11-
12-
1. Name your files with the `.tsx` extension
13-
2. Enable the `jsx` option
14-
15-
TypeScript ships with two JSX modes: `preserve` and `react`.
16-
These modes only affect the emit stage.
17-
The `preserve` mode will keep the JSX as part of the output to be further consumed by another transform step.
18-
Additionally the output will have a `.jsx` file extension.
19-
The `react` mode will emit `React.createElement`, does not need to go through a JSX transformation before use, and the output will have a `.js` file extension.
20-
21-
Mode | Input | Output | File Extension
22-
-----------|-----------|------------------------------|---------------
23-
`preserve` | `<div />` | `<div />` | `.jsx`
24-
`react` | `<div />` | `React.createElement("div")` | `.js`
25-
26-
You can specify this mode using either the `--jsx` command line flag or the corresponding option in your [tsconfig.json](https://github.com/Microsoft/TypeScript/wiki/tsconfig.json) file.
27-
28-
> *Note: The identifier `React` is hard-coded, so you must make React available with an uppercase R.*
29-
30-
# The `as` operator
31-
32-
Since TypeScript uses angle brackets for type assertions, there is a conflict when parsing between type assertions and JSX.
33-
Consider the following code:
34-
35-
```JSX
36-
var foo = <foo>bar;
37-
</foo>
38-
```
39-
40-
Is this code creating a JSX element with the content of `bar;`, or is it asserting that `bar` is of type `foo` and there is an invalid expression on line 2?
41-
To simplify cases like this, angle bracket type assertions are not available in `.tsx` files.
42-
As a result, in a `.tsx` file, the previous code would be interpreted as a JSX element, and in a `.ts` file it would result in an error.
43-
44-
To make up for this loss of functionality in `.tsx` files, a new type assertion operator has been added: `as`.
45-
46-
```TypeScript
47-
var foo = bar as foo;
48-
```
49-
50-
The `as` operator is available in both `.ts` and `.tsx` files.
51-
52-
# Type Checking
53-
54-
In order to understand type checking with JSX you must first understand the difference between intrinsic elements and value-based elements.
55-
Given a JSX expression `<expr />`, `expr` may either refer to something intrinsic to the environment (e.g. a `div` or `span` in a DOM environment) or to a custom component that you've created.
56-
This is important for two reasons:
57-
58-
1. For React, intrinsic elements are emitted as strings (`React.createElement("div")`), whereas a component you've created is not (`React.createElement(MyComponent)`).
59-
2. The types of the attributes being passed in the JSX element should be looked up differently. Intrinsic element attributes should be known *intrinsically* whereas components will likely want to specify their own set of attributes.
60-
61-
TypeScript uses the [same convention that React does](http://facebook.github.io/react/docs/jsx-in-depth.html#html-tags-vs.-react-components) for distinguishing between these.
62-
An intrinsic element always begins with a lowercase letter, and a value-based element always begins with an uppercase letter.
63-
64-
## Intrinsic elements
65-
66-
Intrinsic elements are looked up on the special interface `JSX.IntrinsicElements`.
67-
By default, if this interface is not specified, then anything goes and intrinsic elements will not be type checked.
68-
However, if interface *is* present, then the name of the intrinsic element is looked up as a property on the `JSX.IntrinsicElements` interface.
69-
For example:
70-
71-
```TypeScript
72-
declare namespace JSX {
73-
interface IntrinsicElements {
74-
foo: any
75-
}
76-
}
77-
78-
<foo />; // ok
79-
<bar />; // error
80-
```
81-
82-
In the above example, `<foo />` will work fine but `<bar />` will result in an error since it has not been specified on `JSX.IntrinsicElements`.
83-
84-
*Note: You can also specify a catch-all string indexer on `JSX.IntrinsicElements`* as follows:
85-
86-
```TypeScript
87-
declare namespace JSX {
88-
interface IntrinsicElements {
89-
[elemName: string]: any;
90-
}
91-
}
92-
```
93-
94-
## Value-based elements
95-
96-
Value based elements are simply looked up by identifiers that are in scope.
97-
98-
```TypeScript
99-
import MyComponent from "./myComponent";
100-
101-
<MyComponent />; // ok
102-
<SomeOtherComponent />; // error
103-
```
104-
105-
It is possible to limit the type of a value-based element.
106-
However, for this we must introduce two new terms: the *element class type* and the *element instance type*.
107-
108-
Given `<Expr />`, the *element class type* is the type of `Expr`.
109-
So in the example above, if `MyComponent` was an ES6 class the class type would be that class.
110-
If `MyComponent` was a factory function, the class type would be that function.
111-
112-
Once the class type is established, the instance type is determined by the union of the return types of the class type's call signatures and construct signatures.
113-
So again, in the case of an ES6 class, the instance type would be the type of an instance of that class, and in the case of a factory function, it would be the type of the value returned from the function.
114-
115-
```TypeScript
116-
class MyComponent {
117-
render() {}
118-
}
119-
120-
// use a construct signature
121-
var myComponent = new MyComponent();
122-
123-
// element class type => MyComponent
124-
// element instance type => { render: () => void }
125-
126-
function MyFactoryFunction() {
127-
return {
128-
render: () => {
129-
}
130-
}
131-
}
132-
133-
// use a call signature
134-
var myComponent = MyFactoryFunction();
135-
136-
// element class type => MyFactoryFunction
137-
// element instance type => { render: () => void }
138-
```
139-
140-
The element instance type is interesting because it must be assignable to `JSX.ElementClass` or it will result in an error.
141-
By default `JSX.ElementClass` is `{}`, but it can be augmented to limit the use of JSX to only those types that conform to the proper interface.
142-
143-
```TypeScript
144-
declare module JSX {
145-
interface ElementClass {
146-
render: any;
147-
}
148-
}
149-
150-
class MyComponent {
151-
render() {}
152-
}
153-
function MyFactoryFunction() {
154-
return { render: () => {} }
155-
}
156-
157-
<MyComponent />; // ok
158-
<MyFactoryFunction />; // ok
159-
160-
class NotAValidComponent {}
161-
function NotAValidFactoryFunction() {
162-
return {};
163-
}
164-
165-
<NotAValidComponent />; // error
166-
<NotAValidFactoryFunction />; // error
167-
```
168-
169-
## Attribute type checking
170-
171-
The first step to type checking attributes is to determine the *element attributes type*.
172-
This is slightly different between intrinsic and value-based elements.
173-
174-
For intrinsic elements, it is the type of the property on `JSX.IntrinsicElements`
175-
176-
```TypeScript
177-
declare module JSX {
178-
interface IntrinsicElements {
179-
foo: { bar?: boolean }
180-
}
181-
}
182-
183-
// element attributes type for `foo` is `{bar?: boolean}`
184-
<foo bar />;
185-
```
186-
187-
For value-based elements, it is a bit more complex.
188-
It is determined by the type of a property on the *element instance type* that was previously determined.
189-
Which property to use is determined by `JSX.ElementAttributesProperty`.
190-
It should be declared with a single property.
191-
The name of that property is then used.
192-
193-
```TypeScript
194-
declare module JSX {
195-
interface ElementAttributesProperty {
196-
props; // specify the property name to use
197-
}
198-
}
199-
200-
class MyComponent {
201-
// specify the property on the element instance type
202-
props: {
203-
foo?: string;
204-
}
205-
}
206-
207-
// element attributes type for `MyComponent` is `{foo?: string}`
208-
<MyComponent foo="bar" />
209-
```
210-
211-
The element attribute type is used to type check the attributes in the JSX.
212-
Optional and required properties are supported.
213-
214-
```TypeScript
215-
declare module JSX {
216-
interface IntrinsicElements {
217-
foo: { requiredProp: string; optionalProp?: number }
218-
}
219-
}
220-
221-
<foo requiredProp="bar" />; // ok
222-
<foo requiredProp="bar" optionalProp={0} />; // ok
223-
<foo />; // error, requiredProp is missing
224-
<foo requiredProp={0} />; // error, requiredProp should be a string
225-
<foo requiredProp="bar" unknownProp />; // error, unknownProp does not exist
226-
<foo requiredProp="bar" some-unknown-prop />; // ok, because `some-unknown-prop` is not a valid identifier
227-
```
228-
229-
>*Note: If an attribute name is not a valid JS identifier (like a `data-*` attribute), it is not considered to be an error if it is not found in the element attributes type.*
230-
231-
The spread operator also works:
232-
233-
```JSX
234-
var props = { requiredProp: 'bar' };
235-
<foo {...props} />; // ok
236-
237-
var badProps = {};
238-
<foo {...badProps} />; // error
239-
```
240-
241-
# The JSX result type
242-
243-
By default the result of a JSX expression is typed as `any`.
244-
You can customize the type by specifying the `JSX.Element` interface.
245-
However, it is not possible to retrieve type information about the element, attributes or children of the JSX from this interface.
246-
It is a black box.
247-
248-
# Escaping to TypeScript
249-
250-
JSX in JavaScript allows you to escape to JavaScript by using curly braces `{ }`.
251-
JSX in TypeScript allows you to do the same thing, but you escape to TypeScript.
252-
That means transpilation features and type checking still work when embedded within JSX.
253-
254-
```JSX
255-
var a = <div>
256-
{['foo', 'bar'].map(i => <span>{i/2}</span>)}
257-
</div>
258-
```
259-
260-
The above code will result in an error since you cannot divide a string by a number.
261-
The output, when using the `preserve` option, looks like:
262-
263-
```JSX
264-
var a = <div>
265-
{['foo', 'bar'].map(function (i) { return <span>{i / 2}</span>; })}
266-
</div>
267-
```
268-
269-
# React integration
270-
271-
To use JSX with React you should use the [React typings](https://github.com/borisyankov/DefinitelyTyped/tree/master/react).
272-
These typings define the `JSX` namespace appropriately for use with React.
273-
274-
```TypeScript
275-
/// <reference path="react.d.ts" />
276-
277-
interface Props {
278-
foo: string;
279-
}
280-
281-
class MyComponent extends React.Component<Props, {}> {
282-
render() {
283-
return <span>{this.props.foo}</span>
284-
}
285-
}
286-
287-
<MyComponent foo="bar" />; // ok
288-
<MyComponent foo={0} />; // error
289-
```
1+
> ### This page has moved to http://www.typescriptlang.org/docs/handbook/jsx.html

0 commit comments

Comments
 (0)