Typescript

UWAGA! Ponieważ nastąpił połączenie React z Typescript okazało się wyjątkowo udane, nastąpił znaczący rozwój tego oprogramowania, a poniższe opisy nieco się zdezaktualizowały. Dlatego powstał nowy rozdział książki poświęcony wyłącznie programowaniu w React i Typescript. Zobaczymy w nim, że to co poniżej opisano, można zrobić dużoprościej.

Aplikacje React można tworzyć w Ttypescript. Wymaga to w sumie niewielkich modyfikacji.

Przede wszystkim musimy zbudować projekt "ręcznie" - ewentualnie korzystając z gotowych szkieletów takich jak https://github.com/basarat/react-typescript.git

Konfiguracja projektu

Aby zbydować projekt, powinniśmy wykonać następujące działania:

1) Zainicjowanie projektu:

yarn init

2) Zainstalowanie typescript, react i webpack:

yarn add typescript  react react-dom @types/react @types/react-dom
yarn add webpack webpack-dev-server ts-loader
yarn add webpack-cli -D

3) Modyfikacja utworzonego pliku package.json.

Nie jest nam potrzebny parametr "main", możemy za to dodać definicje skryptów uruchomienia testowego i budowania aplikacji (przy pomocy webpack):

"scripts": {
  "build": "webpack -p",  
  "start": "webpack-dev-server -d --content-base ./public"
},

4) Konfiguracja webpack.config.js

module.exports = {
  entry: './src/index.tsx',
  output: {
    path: __dirname + '/public',
    filename: 'build/app.js'
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },
  module: {
    rules: [
      { test: /\.tsx?$/, loader: 'ts-loader' }
    ]
  }
}

W tym przykładzie możemy zmieniać położenie modułu startowego (entry) i definicję wyjścia.

5) Konfiguracja Typescript - plik tsconfig.json:

{
  "compilerOptions": {
    "sourceMap": true,
    "module": "commonjs",
    "target": "es5",
    "jsx": "react",
    "lib": [
      "dom",
      "es6"
    ]
  },
  "include": [
    "src"
  ],
  "compileOnSave": false
}

Programowanie

Ponieważ Typescript jest nadzbiorem Javascript - konieczne zmiany - poza użyciem typów - nie są wielkie.

w miejsce:

import React from 'react';
import ReactDOM from 'react-dom';

ma być:

import * as React from 'react';
import * as ReactDOM from 'react-dom';

Potem używamy identyfikatorów z odpowiednim przedrostkiem (na przykład ReactDOM.render).

Pliki Typescript w tórych stosujemy JSX powinny mieć rozszerzenia nazwy '.tsx'. Wówczas przy imporcie nie musimy podawać rozszerzeń. Najprostszy przykład możemy stworzyć na bazie https://github.com/tenarjw/react-intro-by-example/tree/master/typescript/simple

W pliku src/index.tsx wpisujemy:

import * as React from 'react';
import * as ReactDOM from 'react-dom';


ReactDOM.render(
  <div>Hello World</div>,
  document.getElementById("root")
);

Uruchamiamy:

yarn install
yarn start

Sprawdzamy działanie na http://127.0.0.1:8080

Własne komponenty

Najprostszy element React definiujemy tak jak w Javascript:

const Najprostszy = (props) => (<p>Najprostszy</p>);

Jeśli chcemy przekazać własności poprzez props i zadeklarować typtego props, wykorzystujemy interfejs interfejs React.SFC

type Props2 = {
  nazwa: string;
}
const KomponentSFC : React.SFC<Props2> = (props) => {
  return <div><b>Bezstanowy z parametrem: </b>
  Nazwa = {props.nazwa}</div>
}

Użycie tych komponentów jest takie samo jak w Javascript:

<Najprostszy />
<KomponentSFC nazwa="test SFC" />

Badziej złożony przypadek - to komponent z wewnetrzym stanem i obsługą zdarzeń:

type Props3 = {
  opis: string;
  srodek: React.ReactNode;
}
type State3 = {
  licznik : number;
}
class Komponent3 extends React.Component<Props3, {}> {
  state : State3;
  constructor(props) {
    super(props);
    this.state = { licznik : 0}
  }

  private klik = (event: React.MouseEvent<HTMLButtonElement>) : void =>
   { this.setState({licznik: this.state.licznik+1})}

  render() {
   return <div><br />Komponent z licznikiem 
   i parametrem JSX (link)<br />
   opis= {this.props.opis}:<br />
   parametr JSX = {this.props.srodek}<br />
   <button onClick={ this.klik }>Kliknij [{this.state.licznik}]
   </button>
   </div>
  }
}

Jak widać - jedyną zmianą jest dodanie typów.

Natomiast samo użycie komponentu nie ulega zmianie:

<Komponent3 opis="test JSX" srodek={<a href="#">OK</a>}/>

Ostatni z przykładów dotyczy komponentu z wartością domyślną własności:

class Hello2 extends React.Component<{
       imie?: string,
       nazwisko: string
       }> {
static defaultProps = {
  imie: 'NN'
}
render() {
  const imie = this.props.imie!;
  return (
  <div>
   <br />
   Z domyślną wartością
   <div>{imie}</div>
   <div>{this.props.nazwisko}</div>
  </div>
);
}
}

Znak zapytania oznacza możliwość braku parametrów. natomiast defaultProps może zawiera wartości domyślne. Użycie:

<Hello2  nazwisko='' />

Spowoduje wyświetlenie NN

Zobacz kompletny przykład [039]