📜 ⬆️ ⬇️

Using React JSX with TypeScript 1.6

Not so long ago, Microsoft announced the release of TypeScript 1.6 Beta , one of the most interesting, in my opinion, innovation is support for React / JSX, which, in conjunction with the features of TypeScript, opens up new possibilities.



I will talk about my personal experience - how I started using the TypeScript + React bundle, what problems I encountered and how I solved them. And also I will show examples of gulp-tasks in order for it to work and demonstrate the code of the minimum todo application in TypeScript + React ( link to Github ).
')
If it is interesting to you - please, come under cat.



TypeScript 1.6


Here are the main changes and additions that brought this update:


A complete list and references to issues can be found on Github . I hope that someone from the community will make a more complete overview of all changes. I will pay attention only to one of them, namely:


Native support JSX


“Wow!” - this is the first thought when I read the announcement . But then the problems started, as it is impossible to simply take and use edge-technologies, so before you start writing cool typed code, we need to work a little in the console to avoid future problems with the assembly and deployment of our code.


Training


By default, we will assume that we have installed and configured the current versions of nodejs and npm .


Installing TypeScript 1.6 Beta


To install TypeScript 1.6 Beta in the global scope, use the command:

npm install -g typescript@1.6.0-beta 

After that, the tsc command will be available in your console - this is actually the compiler for TypeScript. Make sure you have version 1.6-beta installed.

Check that everything is established using the command:

 tsc --version 

For local installation we will use the command:

 npm install typescript@1.6.0-beta --save-dev 


Create package.json


The package.json file contains information about your application: name, version, dependencies, and the like. Any directory that has this file is interpreted as a Node.js package, even if you are not going to publish it.

The method of using the package.json file depends on whether you are going to download the package or publish it. In our case, it will contain a list of dependencies of our project:

 { "name": "tsc-react-gulp-example", "version": "1.0.0", "dependencies": { "react": "^0.13.3" }, "devDependencies": { "browserify": "^11.0.0", "del": "^1.2.0", "gulp": "^3.9.0", "gulp-typescript": "^2.8.0", "typescript": "next", "vinyl-source-stream": "^1.1.0" } } 


Creating gulpfile.js


I used gulp as a project builder, but as for me, there is not much difference, since the main thing is the idea. To build the project, we will use ready-made npm packages: gulp-typescript to compile TypeScript and browserify to work with our project dependencies.


Compiling TypeScript


Task to compile TypeScript is as follows:

 var gulp = require('gulp'), typescript = require('typescript'), ts = require('gulp-typescript'), var project = ts.createProject('src/tsconfig.json', {typescript: typescript}); gulp.task('compile', function () { var result = gulp .src('src/**/*{ts,tsx}') .pipe(ts(project)); return result.js.pipe(gulp.dest('.tmp')); }); 

Here we used the previously reviewed project file. In more detail - on project github page .


browserify


Task to create a project bundle is as follows:

 var gulp = require('gulp'), browserify = require('browserify'), source = require('vinyl-source-stream'); gulp.task('bundle', function () { var b = browserify('.tmp/bootstrap.js'); return b.bundle() .pipe(source('bundle.js')) .pipe(gulp.dest('dist')); }); 


Copying index.html


As an example of working with static files and copying them into gulp, I’ll give an example gulp task for copying index.html to the dist folder:

 gulp.task('through', function () { return gulp .src(['src/index.html']) .pipe(gulp.dest('dist')); }); 


gulpfile.js file


Then the whole gulpfile.js will be like this:

Gulpfile.js source code
 'use strict'; var gulp = require('gulp'), typescript = require('typescript'), ts = require('gulp-typescript'), browserify = require('browserify'), source = require('vinyl-source-stream'), del = require('del'); var project = ts.createProject('src/tsconfig.json', {typescript: typescript}); gulp.task('through', function () { return gulp .src(['src/index.html']) .pipe(gulp.dest('dist')); }); gulp.task('compile', function () { var result = gulp.src('src/**/*{ts,tsx}') .pipe(ts(project)); return result.js.pipe(gulp.dest('.tmp')); }); gulp.task('bundle', ['through','compile'], function () { var b = browserify('.tmp/bootstrap.js'); return b.bundle() .pipe(source('bundle.js')) .pipe(gulp.dest('dist')) ; }); gulp.task('clean', function (done) { del(['.tmp'], done.bind(this)); }); 



TypeScript Definitions


Now I will not dwell on the description of TypeScript Definitions, a lot of cool articles have been written about it. Let me just say that in order to be able to use libraries written in JS for them you need to use these same TypeScript Definitions. And there is even a whole open source project in which people write such definitions for popular projects. They can be searched and downloaded on the site , or you can install a console utility which will simplify this process:

 npm install -g tsd 

Using this utility, we will download the definitions for React and save the TypeScript Definition entry in the tsd.json file:

 tsd query react --action install --save 

The note:

The project is in open source, developed and actively supported by the community - borisyankov / DefinitelyTyped .


Creating tsconfig.json


The tsconfig.json file stores the compilation settings for your project. This file is supported by the compiler since version 1.5. The minimum tsconfig.json that allows you to compile files for React / JSX is as follows:

 { "compilerOptions" : { "module" : "umd", "jsx" : "react" } } 


React code


For an example of how the TypeScript + React bundle works, we will write the minimum todo application.


todoItem.tsx component


Let's start with the smallest brick, namely - TodoItem. Add TypeScript Definition for React to the top of the file:

 /// <reference path="../../typings/react/react.d.ts" /> 

Then we import React into our class:
 import * as React from 'react'; 

Define the ITodo interface for the item:

 interface ITodo { description: string; } 

As well as interfaces for the state and properties of our component:
 export interface ITodoItemState {} export interface ITodoItemProps { item: ITodo; onRemove?: (todo: ITodo) => any; key?: number; } 

Then the component itself will look like this:

 export class TodoItem extends React.Component<ITodoItemProps, ITodoItemState> { constructor () { super(); this.removeItem = this.removeItem.bind(this); } removeItem () { this.props.onRemove(this.props.item); } render () { return ( <li> <span> {this.props.item.description} </span> <button onClick={this.removeItem} >delete</button> </li> ); } } 


main.tsx component


This component will contain the main logic of the application. The principle is the same as in the TodoItem component, so I’ll give a full listing of the file:

main.tsx
 /// <reference path="../../typings/react/react.d.ts" /> import * as React from 'react'; import {TodoItem} from './todoItem'; interface ITodo { description: string; key: number; } export interface IMainState { newItem?: { description: string; }; todoList?: ITodo[]; } export interface IMainProps {} export class Main extends React.Component<IMainProps, IMainState> { state: IMainState = {newItem: {description: ''}, todoList: []} constructor () { super(); this.changeName = this.changeName.bind(this); this.addItem = this.addItem.bind(this); this.removeItem = this.removeItem.bind(this); } changeName (e: any) { this.setState({ newItem: { description: e.target.value } }); } addItem () { var list = this.state.todoList; list.push({ description: this.state.newItem.description, key: new Date().getTime() }); this.setState({ todoList: list, newItem: {description: ''} }); } removeItem (item: ITodo) { var list = this.state.todoList.filter(i => i.key !== item.key); this.setState({todoList: list}); } render () { var todoItems = this.state.todoList.map(item => { return <TodoItem key={item.key} item={item} onRemove={this.removeItem} ></TodoItem>; }); return ( <div> <div> <input type="text" placeholder="input new item" value={this.state.newItem.description} onChange={this.changeName} /> <button onClick={this.addItem} >add</button> </div> <ul>{todoItems}</ul> </div> ); } } 



bootstrap.ts


This file serves as a starting point for the application and contains the logic for calling the main component:

 /// <reference path="../typings/react/react.d.ts" /> import * as React from 'react'; import {Main} from './Main/main'; React.render(React.createElement(Main), document.getElementById('main')); 


index.html


Since we didn’t add any styles, etc., the source code of the file would be:

 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>tsc-react-example</title> </head> <body> <div id="main"></div> <script src="bundle.js"></script> </body> </html> 


Launch and fireworks



Installation and Compilation


After all the files, folders, and tasks have been created, run:

 npm install 

to install all packages and:
 gulp bundle 

to compile our application.


Launch


It's all very prosaic - we set our favorite server to the dist folder and enjoy the results, like this:

 cd dist npm install -g http-server http-server -p 3000 

Then we go to localhost: 3000 / index.html and test.


Instead of conclusion


All code presented in this mini guide can be found at the link . Any comments and suggestions are welcome.

Thanks for attention.

Happy coding!

Source: https://habr.com/ru/post/266665/


All Articles