0
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

(Reactにおける)はじめてのTypeScript

Last updated at Posted at 2022-08-31

使用主言語をJavaScriptからTypeScriptへ転換しようと試みている、そのための大雑把な備忘録リスト。

(なおAngular version7, 8でTypeScriptを書いていたが、Angularはすべてクラス型コンポーネントだったしやはりReactとは違いが色々ありすぎでReact系をTypeScriptで…となると当時の知識は使えない:disappointed_relieved:

準備編

TypeScriptインストールコマンド

npm install typescript @types/node @types/react @types/react-dom

react-router-domをインストールしていたらさらに

npm install @types/react-router-dom

tsconfig.json作成コマンド

npx tsc --init

スタンダードなtsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

JavaScriptとの比較編

デフォルトのindex.jsファイルをTypeScriptにする(index.js → index.tsx)

  • JavaScript
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);
  • TypeScript
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
    <App />
);

as HTMLElementを追加

ステート変数宣言

  • JavaScript
const [loading, setLoading] = useState(false);
const [city, setCity] = useState("");
  • TypeScript
const [loading, setLoading] = useState<boolean>(false);
const [city, setCity] = useState<string>("");

ステート変数宣言(複数をまとめる形式)

  • JavaScript
  const [results, setResults] = useState({
    country: "",
    cityName: "",
    temperature: 0,
    conditionText: "",
  })
  • TypeScript
type ResultsStateType = {
  country: string;
  cityName: string;
  temperature: number;
  conditionText: string;
}

const [results, setResults] = useState<ResultsStateType>({
  country: "",
  cityName: "",
  temperature: 0,
  conditionText: "",
  icon: "",
})

typeで型定義宣言。ResultsStateTypeは任意の名前。ResultsStateTypeでいくつかのステート変数をまとめて型定義している.

ステート変数宣言(配列形式)

  • JavaScript
const [allCountriesData, setAllCountriesData] = useState([])
  • TypeScript
type AllCountryDataType = {
  Country: string,
  NewConfirmed: number,
  TotalConfirmed: number,
}

const [allCountriesData, setAllCountriesData] = useState<AllCountriesDataType>([{
   Country: "",
   NewConfirmed: 0,
   TotalConfirmed: 0,
}])

JavaScriptならカラの配列である、というだけで何も文句は言われない。TypeScriptでは具体的にどんな要素データが配列に入るか、まずは明示する必要がある。

const [allCountriesData, setAllCountriesData] = useState([{
    Country: "",
    NewConfirmed: 0,
    TotalConfirmed: 0,
}])

その上で、以下のようにtypeで型定義する。

type AllCountryDataType = {
  Country: string,
  NewConfirmed: number,
  TotalConfirmed: number,
}

ステート変数宣言(配列形式)― typeの代わりにinterfaceを使う場合

  • TypeScript
interface SingleCountriesDataType {
  Country: string,
  NewConfirmed: number,
  TotalConfirmed: number,
}
interface AllCountriesDataTypeArray extends Array<SingleCountriesDataType>{}

  const [allCountriesData, setAllCountriesData] = useState<AllCountriesDataTypeArray>([{
    Country: "",
    NewConfirmed: 0,
    TotalConfirmed: 0,
  }]) 

ひとつ目のinterfaceで定義しているのは一個の{}データなのでSingleCountriesDataTypeという名前にしている(分かりやすくするためだけ)。別にAllCountriesDataTypeでもCountriesDataTypeでも良い。

そして
AllCountriesDataTypeArray extends Array<SingleCountriesDataType>{}
によって、AllCountriesDataTypeArraySingleCountriesDataTypeを拡張した配列であることを明示している。

最後にくっついている{}はおまじない的なオマケ。

関数に渡されるFormのイベントe

  • JavaScript
  const getInfo = (e) => {
      e.preventDefault();
// ・・・省略・・・
  }
  • TypeScript
  const getInfo = (e: React.FormEvent<HTMLFormElement>) => {
      e.preventDefault();
// ・・・省略・・・
  }

フォームイベントeは、Reactが定義している型React.FormEvent<HTMLFormElement>となる

propsに渡されたステート関数(ここではprops.setCity

  • JavaScript

(propsを渡してる側のコンポーネント)

const [city, setCity] = useState("");
// ...
<Form setCity={setCity} getInfo={getInfo} />

(propsを渡されてる側のコンポーネント)

const Form = (props) => {
    return (
        <form>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Submit</button>
        </form>
    );
};
  • TypeScript

(propsを渡してる側のコンポーネント)

const [city, setCity] = useState<string>("");
// ...
<Form setCity={setCity} getInfo={getInfo} />

(propsを渡されてる側のコンポーネント)

type FormPropsType = {
    city: string;
    setCity: React.Dispatch<React.SetStateAction<string>>;
}

const Form = (props: FormPropsType) => {
    return (
        <form>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Submit</button>
        </form>

    );
};

定義されたFormPropsTypepropsに設定(props: FormPropsType)。
ステート関数setCityの型はReact.Dispatch<React.SetStateActionというもので、useStateの内部で行われる操作系型らしい。。。

propsに渡された関数(ここではprops.getInfo

  • JavaScript

(propsを渡してる側のコンポーネント)

const getWeather = (e) => {
// ...処理
}
// ...省略...
<Form setCity={setCity} getInfo={getInfo} />

(propsを渡されてる側のコンポーネント)

const Form = (props) => {
    return (
        <form onSubmit={props.getInfo}>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Get Info</button>
        </form>

    );
};
  • TypeScript

(propsを渡してる側のコンポーネント)

const getWeather = (e: React.FormEvent<HTMLFormElement>) => {
// ...処理
}
// ...省略...
<Form setCity={setCity} getInfo={getInfo} />
type FormPropsType = {
    city: string;
    setCity: React.Dispatch<React.SetStateAction<string>>;
    getInfo: (e: React.FormEvent<HTMLFormElement>) => void;
}

const Form = (props: FormPropsType) => {
    return (
        <form onSubmit={props.getInfo}>
            <input type="text" name="city" onChange={e => props.setCity(e.target.value)} value={props.city} />
            <button type="submit">Get Info</button>
        </form>
    );
};

eが無ければgetInfo: => void;で良い(void型)。しかしフォームイベントeがあるからgetInfo: (e: React.FormEvent<HTMLFormElement>) => void;となる。

propsに渡されたjsonデータ(ここではprops.countriesJson

(propsを渡してる側のコンポーネント)

<TopPage countriesJson={countriesJson} setCountry={setCountry} />
  • JavaScript
const TopPage = (props) => {
    return (
        <div>
            <Selector countriesJson={props.countriesJson} setCountry={props.setCountry}
        </div>
    );
};
  • TypeScript
type TopPageType = {
    countriesJson:{
        Country: string,
        Slug: string,
    }[],
    setCountry: React.Dispatch<React.SetStateAction<string>>,
}


const TopPage = (props: TopPageType) => {
    return (
        <div>
            <Selector countriesJson={props.countriesJson} setCountry={props.setCountry}
        </div>
    );
};

ここではJSONデータの要素(Country, Slug)が共にstring型。また、JSONでは複数の{}が[]に挟まれている形式であるがゆえに[],を追加する必要がある。React.Dispatch<React.SetStateAction<string>>は前述(propsに渡されたステート関数)


備考:型定義をひとつのファイルにまとめる

大規模開発ではひとつのファイルにまとめてしまう事があるらしい。

  • 手順
    1.場所はどこでも良いがtypes.tsファイル(名前は任意)を新規作成する。
    2.各コンポーネントで定義した型定義コードをtypes.tsに移す(カット&ペースト)。
    3.types.tsにペーストしてきた型定義コードは必ずexportさせる。
    例:↓
export type CountryDataType = {
    date: string,
    newConfirmed: number,
    totalConfirmed: number,
    newRecovered: number,
    totalRecovered: number,
}

4.カットされた各コンポーネントでは、使用していた型定義をtypes.tsからインポートする。
例:↓

import { CountryDataType, AllCountriesDataTypeArray } from "./type"

◆参考:[はじめてさわるReact & JavaScript with TypeScript Kindle版 三好アキ著]


本の宣伝

Gatsbyバージョン5>>>>改訂2版

前編の『Gatsby5前編ー最新Gatsbyでつくるコーポレートサイト』と後編の『Gatsby5後編ー最新GatsbyとmicroCMSでつくるコーポレートサイト《サイト内検索機能付き》』を合わせ、次のようなデモサイトを構築します。
https://yah-space.work


静的サイトジェネレーターGatsby最新バージョン5の基本とFile System Route APIを使用して動的にページを生成する方法を解説。またバージョン5の新機能《Slicy API》《Script API》《Head API》を紹介、実装方法も。《Gatsby Functions》での問い合わせフォーム実装やGatsby Cloudへのアップロード方法も!


Gatsby5前編ー最新Gatsbyでつくるコーポレートサイト ~基礎の基礎から応用、新機能の導入まで(書籍2,980円)



最新Gatsby5とmicroCMSを組み合わせてのコーポレートサイト作成手順を解説。《サイト内検索機能》をGatsbyバージョン4からの新機能《Gatsby Functions》と《microCMSのqパラメータ》で実装。また、SEOコンポーネントをカスタマイズしてmicroCMS APIをツイッターカードに表示させるOGPタグ実装方法も解説。


Gatsby5後編ー最新GatsbyとmicroCMSでつくるコーポレートサイト《サイト内検索機能付き》(書籍 2,790円)



0
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?