👌

How to migrate from javascript to typescript on react

2022/05/22に公開

Get Started

I talk about migrating from javascript to typescrit on react.

There are three ways to typescript.

Both methods require the typescript library to be installed.

directly to migrate to typescript

Significantly change the project by changing all file extensions from js, mjs, jsx to ts.

Advantages

  1. The method is orthodox.

Disadvantages

  1. In the operational phase, it is difficult to take this approach.

using allowJS

Add allowjs key in tsconfig.json

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "baseUrl": "src",
    "lib": [
        ...
    ],
    "allowJs": true,
    ...
  }
}

Advantages

  1. Can use both js and ts.

Disadvantages

  1. It is difficult to isolate problems when they occur.

using @ts-check

If you write a comment in jsdoc format and @ts-check at the top of the file, vscode will show type hints and use them.

jsdoc形式のコメントを書いて、ts-checkをファイルの一番上に書くとvscodeが型ヒントを表示してくれるのでそれを使う。

In addition, using ts-check, javascript can be handled as safely as typescript because the syntax checks are the same as those of typescript with a few exceptions.

またts-checkを使うと、typescriptと一部を除いて同じ構文チェックが入るため、typescriptと同じぐらい安全にjavascriptと扱う事ができる。

You can also check linter like eslint, pretieer as typescript, and it will be displayed as an error on vscode.

vscodeでexpressエラーの表示

In fact, since microsoft is also proposing to include type hints in javascript and is close to that approach, it is likely to work even if typescript becomes legacy.

実はmicrosoftもjavascriptに型ヒントを入れようと、提案していてそのやり方に近いため、typescriptがレガシーになっても通用する可能性が高い。

micrsoft proposal

example.js
// @ts-check
// Write @ts-check on the first line of the file.

// example variable
/** @type {number} */
let count = 0;

// if you do not know type or convert dificulty to typescript,
// use @ts-ignore, this comment ignore typescript check.


// @ts-ignore


components/.js
// @ts-check
// example react components

// interface

pages/purchase.js
// @ts-check
// example next

/**
 * @description example next pages
 * @param {{csrfToken: string}} _ 
 * @returns {JSX.Element}
 */
export default function PurchasePage({csrfToken}) {
    ...

   /**
   * @description submit function using react hook form.
   * @param {{merchandise1: string}} data
   * @param {React.BaseSyntheticEvent} event
   */
  const submitForm = (data, event) => {

    /** @type {HTMLFormElement} */
    const form = document.querySelector('#post_form');

    /** @type {HTMLButtonElement} */
    const form_button = form.querySelector('button');

    /** @type {HTMLInputElement} */
    const email = document.querySelector('input[name="merchandise1"]');

    email.value = getValues('merchandise1');

    // fire click event. and post.
    form_button.click()
  }
  ...
  return (
      <div>
      ...
      </div>
  )
}

/**
 * @description example next + customserver(express)
 * @param {{req: import('express').Request; res: import('express').Response}} _ 
 * @returns {Promise<{props: {csrfToken: string;};}>}
 */
export async function getServerSideProps({ req, res }) {

  const csrfToken = req.csrfToken();
  return {
    props: {
      csrfToken
    },
  }
}

Advantages

  1. Typescript conversion can proceed in parallel with development.
  2. No need to include tools for building ts.
  3. It is only a comment, so it does not interfere with the build of react and next.

DisAdvantages

  1. Sometimes it is necessary to read the source code of the nodejs library to be used in order to write a jsdoc with the correct type.It will be necessary to read the source code of the nodejs library to be used in order to write a jsdoc with the correct type.
  2. Development speed is slower than javascript alone and need to know nodejs configuration and specifications
  3. Javascript can get caught up in typescript bugs. Sometimes you need to check for issues on github.

(example3) nodejs package subpath pattern

Because of this bug, an error is displayed on vscode even though the path to the project library passes.

subpath pattern

In this article, we will explain how to directly typescript the javascript in 1.

今回は1のjavascript

Prepation

editor

Since vscode works well with typescript intellisense and also with lint
You should use vscode. I don't recommend vim very much. vscode with a vim plugin and be patient.

vscodeがtypescriptのインテリセンス、またlintと相性がいいので、
vscodeを使うべき。 vimはとてもじゃないが、おすすめできない。vscodeにvimのプラグインを入れて我慢してください。

使うことが推奨される拡張を並べておく。
これらをvscodeの拡張としてインストールしておくこと。

The extensions that are recommended to be used are listed below.
These should be installed as extensions to vscode.

  • dsznajder.es7-react-js-snippets
  • ms-vscode.vscode-typescript-next
  • dbaeumer.vscode-eslint
  • esbenp.prettier-vscode

With vimmer, install the following as well. Note that this extension has some vim commands that aren't available yet. (Commands such as :m,:g)

vimmerなら下記のものもインストールする。なお、この拡張にはまだ使えるようになっていないvimコマンドがあるので注意すること。(:m, :g などのコマンドとか。)

  • vscodevim.vim

addt ypescript library

Add typescript, @types/node,@types/react,@types/reactRouter,@types/reactDom,@types/jest,@types/materialUi, etc. (At this point, do not add lint libraries for simplicity, as they cause errors during build.)

typescript,react,reactRouter,reactDom,jest,materialUiなどの@types追加(この時点では簡単のため、lint系のライブラリーを追加しない。build時にエラーが出るため。)

# Look up necessary @types, etc.
yarn add --dev typescript @types/node-sass @types/node @types/jest @material-ui/types @types/react @types/react-dom

# npm install
npm install --seve-dev typescript @types/node-sass @types/node @types/jest @material-ui/types @types/react @types/react-dom

generate tsconfig.json

Create another project to create a configuration file.
This method is recommended because the configuration of tsconfig.js is difficult to write thoughtfully and is a source of syntax errors.

設定ファイル作成のため、他にプロジェクトを作成する。
tsconfig.jsの設定は考えて書くのは難しく、シンタックスエラーの元になるので、このやり方推奨。

create-react-app <dummy_project> --template typescript

Copy the generated tsconfig.json and insert it into the new project you want to typescript.

生成されたtsconfig.jsonをコピーして
新しくtypescript化したいプロジェクトに突っ込んでおく。

Replace jsconfig.js with tsconfig.js

If the jsconfig.json file was used in the project that you want to typescript,
move the settings to tsconfig.js because typescript cannot use jsconfig.js.

もし、typescript化したいプロジェクトでjsconfig.jsonファイルを使っていた場合、
typescriptではjsconfig.jsを使えないため、設定をtsconfig.jsに移す。

jsonfig.json
{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "*": ["src/*"]
    }
  }
}
tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "baseUrl": "src",
    "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"
  ]
}

Just put the setting in the corresponding key and that's it.
jsconfig.json must be deleted. If you leave it, the build will fail.
(If you really want to keep it, you can change the extension to something like .txt, but it's not necessary if you're using git.)

対応するキーに設定を入れたらそれで良い。
jsconfig.jsonは削除しておくこと。残しておくとビルドに失敗する。
(どうしても残したいなら.txtみたいに拡張子変えればいいけど、git使ってるなら必要ない。)

You want to check if there are any problems with tsconfig.json, etc. here, so please build it.
If it works, no error will occur.

ここでtsconfig.jsonなどに問題無いかチェックしたいのでビルドしてみてください
うまくいっていればエラーは発生しません。

yarn build

Fix import of each js file

You eliminate the .js extensions for the from part as shown below.

Using the editor's replace function makes it easier, but be aware that it is easy to get other strings involved.
You check the git diff to make sure you have replaced it correctly.

下記のようにfrom部分が.jsとjsの拡張子になっているものの拡張子を無くす。
javascriptからtypescriptだから当然。

エディタの置換機能を使うと楽になるが、他の文字列を巻き込みやすいので注意。
gitの差分を見て正しく置換できているか確認すること。

// import Hello from 'components/hello.js'
import Hello from 'components/hello'

Change the file extension to typescript

You change .js to .ts extension.
This process can be written in bash, but pwsh is easier to write and more secure script.
pwsh is recommended. linux and mac users should install and use pwsh.

The following is how to write the script assuming that the js files are under the src folder.
The same way to write .jsx to .tsx.

.jsを.tsに変更することによりtypescriptに変更します。
この処理はbashでも書けるが、pwshのほうが書きやすく安全なスクリプトになるので
pwsh推奨。linux, macの人はpwshをインストールして使ってみよう。

下記はsrcフォルダ以下にjsファイルがあると想定した時の書き方。
jsx->tsxも同じ要領で書く。

#  -WhatIf to check if the assumed file is renamed
# -WhatIfにより、想定されたファイルがリネームされるかどうか確認
Get-ChildItem -Recurse src/ |
  Where-Object {$_.Name -match ".js$"} | 
  Rename-Item -NewName { $_ -replace "\.js$", ".ts" } -WhatIf

# Change file extension.
# ファイルの拡張子を変更。
Get-ChildItem -Recurse src/ |
  Where-Object {$_.Name -match ".js$"} | 
  Rename-Item -NewName { $_ -replace "\.js$", ".ts" }

Let's build again here.
I think I get an error message about not knowing the type, etc.
It is recommended to commit and push once to the newly created branch around here.
It is hard to get backtracking from here.

ここでもう一度ビルドしてみよう。
型がわからないなどのエラーが出ると思う。
ここら辺で新しく作ったブランチに一度コミット、pushしてみては?
ここから後戻りが出ると大変です。

Typescript conversion of linter-based libraries

linter系のライブラリーを追加する

yarn add --dev @typescript-eslint/eslint-plugin @typescript-eslint/parser

Change .eslintrc.js as follows.
It is important to note that the parser changes from babel to typescript-eslint.

.eslintrc.jsを下記のように変更。
変更追加が必要なもののみ書いています。parserがbabelからtypescript-eslintに変わるのは重要です。

eslintrc.js

  // parser: "babel-eslint",
  parser: "@typescript-eslint/parser",
  plugins: ["react", "@typescript-eslint"],
  rules: {
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": "error",
  },

.babelrc.js should be removed.
It is not needed in typescript unless there is a specific reason.

.babelrc.jsは削除しておく。
typescriptでは特に理由が無い限り不要。

You try building again.
If there are no errors in the library itself, you are good to go.
From this point on, we will make serious changes to the source code.
I recommend committing once around here.

もう一度ビルドしてみます。
ライブラリ自体のエラーが出ないなら大丈夫です。
これよりあとは本格的にソースコードを変更します。
ここら辺で一度コミット推奨。

Change source code javasctip to typescript

これ以降は下のように考えながら修正していきます。js,tsどちらの知識も必要です。

  • ビルド時にどんなエラーがでるか
  • vscodeに赤文字でlintとして何が問題か

ひっかかりそうなエラーを下に書いていきます。

From this point onward, we will modify it as we think below. knowledge of both js and ts is required.

  • What errors do you get at build time?
  • What is the problem as lint in red text in vscode.

The errors that may be caught and how to fix them are described below.

Error on makeStyles

There is a problem with the object in which the style definition is written.

スタイルの定義が書かれているオブジェクトに問題があります。

const useStyles = makeStyles(styles);

components/Hello.js

const HelloStyle = {
    root: {
      flexGrow: 1,
      marginBottom: "20px",
    }
};

const useStyles = makeStyles(HelloStyle);

//

If you are specifying a style with an object like
createStyles.

みたいにオブジェクトでstyleを指定しているなら、
createStylesを使ってください。

components/HelloStyle.ts
import { createStyles } from "@material-ui/core/styles";

const HelloStyle = createStyles({
    root: {
      flexGrow: 1,
      marginBottom: "20px",
    }
});

const useStyles = makeStyles(HelloStyle);

//

If you are using theme, you must explicitly state that it is a Theme type or you will get an error.

themeを使っている場合は、Theme型であると明示しないとエラーになります。
typescriptだから当然ですね

components/HelloStyle.ts
import { createStyles, Theme } from "@material-ui/core/styles";

const HelloStyle = (theme: Theme) =>
createStyles({
    root: {
    flexGrow: 1,
    marginBottom: "20px",
    }

    /// ... これ以降に引数のthemeを使っているとする。
});

const useStyles = makeStyles(HelloStyle);

// ...

Error caused by change to createStyles

fontWeight

If you change it to createStyles, you may get an error in the key.
For example, see below.

createStylesと変更するとキーにエラーが発生する場合があります。
例えば、下をみてください。

components/HelloStyle.ts
import { createStyles } from "@material-ui/core/styles";

const HelloStyle = createStyles({
    root: {
      flexGrow: 1,
      marginBottom: "20px",
      fontWeight: "500",
    }
});

const useStyles = makeStyles(HelloStyle);

Perhaps there is an error with fontWeight.
Since it is typescript, string type is not allowed. So, I'm not sure if you are getting a
error occurred. If you simply took the "" and made it a NUMBER, it would not be an error.

I am writing styles in separate files for each class name, and I don't want to mess with the original files.
If you don't want to mess with the original file, you need to write the following.

If you don't know the scope of the effect of the change, you have to write it like this.

Translated with www.DeepL.com/Translator (free version)

恐らく、fontWeightでエラーが発生していると思います。
typescriptにしたのでstring型は許されない。ということなので、
エラーが発生したのです。単純に""をとってnumberにしたらエラーでなくなります。

class名ごとに別のファイルにスタイルを分けて書いていて、
元のファイルをいじりたくないなら下記のように書く必要がある。

変更による影響範囲がわからないなら、こう書くしか無い。

assets/HelloStyle.ts
import {
  title
} from "style/title";
import { createStyles } from "@material-ui/core/styles";
const HelloStyle = createStyles({
  // 本来ならクラス名を表すオブジェクトであるtitleをそのまま書いたらいいだけ
  // のはずだが、fontWeightがstring型で入っているので、parseIntにより変更する。
  // title,
  title: {
    ...title,
    fontWeight: parseInt(title.fontWeight),
  },

Property only accepts certain strings, but lint doesn't understand it

The as(cast) makes it explicit that it is a specific string.

as(キャスト) により特定の文字列であることを明示する。

assets/HelloStyle.ts
import {
  title
} from "style/title";
import { createStyles } from "@material-ui/core/styles";
const HelloStyle = createStyles({
  // Normally, you would just write title, which is an object representing the class name, as it is However, since lint cannot determine whether position is a specific string or not, it casts the type explicitly.
  // 本来ならクラス名を表すオブジェクトであるtitleをそのまま書いたらいいだけ
  // のはずだが、lintがpositionが特定の文字列か判断できないため、型を明示的にキャストする。
  // title,
  title: {
    ...title,
    position: title.position as
      | "static"
      | "relative"
      | "absolute"
      | "sticky"
      | "fixed",
    fontWeight: parseInt(title.fontWeight),
  },

Error because the type of the props argument of the component function is not known

This can only be determined by taking a closer look at the source code OR
You need to ask the person who wrote the source code to identify it.
Ask the person who wrote the code what he/she intended to do as much as possible.

You are supposed to define the argument types using interface.
interface, it is recommended to refer to the types accepted by PropTypes as shown below.
If not, the programmer must determine the type from the source code.

Please refer to the following.

Translated with www.DeepL.com/Translator (free version)

これはソースコードをじっくりみる or
書いた人に聞かないと判別できない。
できるだけ書いた人に何を想定していたか聞くこと。

interfaceを使って引数の型を定義していくことになるが、
interfaceのプロパティは下記のようにPropTypesで受け付ける型を参考にすることとよい。
なければ、ソースコードからプログラマが判断するしかない。

下記を参考にして欲しい。

assets/HelloStyle.ts
import PropTypes from "prop-types";

// PropTypesを参考にプロパティの型を考える。
interface Props {
  active: number | number[];
  color?:
    | "warning"
    | "danger"
    | "success"
    | "info";
}

export default function HelloComponent(props: Props) {
// props
//
}

HelloComponent.propTypes = {
  // index of the default active collapse
  active: PropTypes.oneOfType([
    PropTypes.number,
    PropTypes.arrayOf(PropTypes.number),
  ]).isRequired,
  color: PropTypes.oneOf([
    "warning",
    "danger",
    "success",
    "info",
  ]),
};

Extend or composite of interface

Typescript can both extend and composite (in the form of having the interface in the interface's properties) the interface.

For example, which is better with a component called CustomButton?
As it turns out, the one with fewer changes is better. Most of the time, composites change less and are more resistant to change.

Using extends can cause problems like the one below.
Be aware that when such changes occur, the number of modifications will increase.

Translated with www.DeepL.com/Translator (free version)

typescriptはinterfaceのextendもコンポジット(interfaceのプロパティにinterfaceを持たせるという形で)も両方できる。 \

例えば、CustomButtonというコンポーネントとどちらの方がいいか?
結論から言うと変更が少ない方が良い。大抵の場合はコンポジットの方が変更が少なく、変更に強い。

extendsを使うと下のような問題が起きる可能性がある。
このような変更が起きると修正箇所が増えるので気をつけること。

components/HelloComponents.ts

import { Props as CustomButtonProps } from 'components/CustomButton'
import { Props as CustomDiverProps } from 'components/CustomDiver'

interface Props extends CustomButtonProps, CustomDiverProps {
  active: number | number[];
  
}

export default function HelloComponent(props: Props) {
// props
//
}

In this case, if CustomButtonProps and CustomDiverProps each have properties with the same name
and the type is different, a type mismatch will result in an error.
A common case is when the inheriting Prop has a property with the common name "color".
In the above example, CustomButtonProps and CustomDiverProps both have a property named "Color", and if the type of the property is different from that of the inherited props, a Color mismatch error will occur.
In the above example, both CustomButtonProps and CustomDiverProps have a property named "Color", and if the types are different, it is necessary to align the type of Color.
Even if one has a normal type and the other has an optional type (color?:), an error will occur.

The recommended way to avoid this is compositing. I want you to see below.

このとき、CustomButtonProps, CustomDiverPropsそれぞれに同じ名前のプロパティがあり、
なおかつ型が違う場合は型不一致でエラーになる。
よくあるのが、colorというよくある名前のプロパティを継承元のPropsが持っている場合。
上の例だとCustomButtonProps, CustomDiverPropsともにColorというプロパティを持っており、
かつ型が違う場合はColorの型を揃える必要があるため、修正があった場合の影響範囲が大きくなる。
片一方が普通の型でもう片一方がオプショナル型(color?:)でもエラーになる。

これを避けるためにおすすめなのがコンポジットだ。下を見て欲しい。


import { Props as CustomButtonProps } from 'components/CustomButton'
import { Props as CustomDiverProps } from 'components/CustomDiver'

interface Props {
  active: number | number[];
  CustomButtonProps: CustomButtonProps;
  CustomDiverProps: CustomDiverProps;
  
}

export default function HelloComponent(props: Props) {
// props
//
}

If you don't use only certain properties, like below You can also use type definition with type only for specific properties, as shown below.

もし、特定のプロパティだけ使わないなら下のように
下のように特定のプロパティだけtypeで型定義をするという方法もある。


import { Props as CustomButtonProps } from 'components/CustomButton'
import { Props as CustomDiverProps } from 'components/CustomDiver'

// interfaceのプロパティの定義へのアクセスは.(ドット)でなくて、["プロパティ名"]とする必要がある。
type CusomButtonPropsColor = CusomButtonProps["color"];
type CustomDiverPropsColor = CustomDiverProps["color"];

interface Props {
  active: number | number[];
  CustomButtonPropsColor: CusomButtonPropsColor;
  CustomDiverProps: CustomeDiverPropsColor;
  
}

export default function HelloComponent(props: Props) {
// props
//
}

rest parameter in props

In javascript, the following will take the object's key out of the variable and A new variable can be assigned.

javascriptでは下記のようにすると、変数からオブジェクトのキーを取り出して、
新たに変数を割り当てることができる。

const point = {
  x: 34,
  y: 12,
  z: 100
};

const { 
  x,
  ...rest
  } = point;

// The value of REST is shown below.
// restの値は下のようになっている。
// rest = {
//   y: 12
//   z: 100
// }

In the above case, the variable x contains the value of key x in point, and all other keys go into rest.
In react, this is used when you want to pass the properties of props to other components, as shown below.
to other components, as shown below.

In this case, we need to add the *interface property to the rest parameter so that it can receive the key properly, as shown below.
Interface property with the key assumed to be the rest parameter so that it can receive the key in the rest parameter as shown below.

上の場合は変数xにpointのキーxの値が入り、それ以外のキーは全てrestに入る。
reactでどういうときにこれを使うかというと、下のようにPropsのプロパティをさらに、
他のコンポーネントに渡す時だ。

この場合は下のようにrestパラメーターでちゃんとキーを受けれるように、
interfaceのプロパティにrestパラメーターとして想定しているキーを書く必要がある。

import Grid, { GridSize } from "@material-ui/core/Grid";

interface Props {
  x: number;
  color?:
    | "danger"
    | "success"
    | "info";
  xs?: GridSize;
}

export default function HelloComponent(props: Props) {

  const { 
    x,
    color,
    ...rest
    } = props;
  return (
    <Grid item {...rest} >
      {children}
    </Grid>
  );
// props
//
}

Props properties are object types, and their behavior is different depending on whether the key is present or not

Since javascript can easily add keys dynamically, the following code can also be written.

javascriptは動的にキーを簡単に追加できるので、下記のようなコードもかけます。


export default function HelloComponent(props) {
// props
//
}

// NAME is not a boolean value, nor is it necessarily a property to have in the first place.
// nameは真偽値でもないし、そもそもプロパティとして持っているとは限らない。
if (props.name) {
  ...
  // Enter the process using the value of name.
}

Personally, I think it's best not to make use of such js specifications in the first place unless you have time to think it through carefully, otherwise it will become a breeding ground for bugs.
I think it's best not to do it unless you have time to think it through thoroughly, and usually you tend to create bugs that you don't understand.
ts will also cause errors depending on the type, so please check the existence of the property without being side-tracked as shown below.

個人的にはそもそもそんなjsの仕様を利用した作りは丁寧に作らないとバグの温床になるため、
しっかり考える時間がない限りやめた方がいいと思いますし、たいていよくわからないバグを作りがちです。
tsでも型によりエラーになるので、下記のように横着せずプロパティの存在を確認してください。

components/HelloComponents.ts

interface Props {
  name?: string
}

export default function HelloComponent(props: Props) {
// props
//
}

// If name exists and is not empty, it is processed.
// nameが存在して、空文字でなければ処理に入る。
if ("name" in props && props.name !== "") {
  ...
}

bracket notation

If you're not very familiar with javascript, you'll be amused. javascript can dynamically create objects using variables that may be undefined as shown below as keys. It is possible to create objects dynamically.

javascriptにあまり詳しくない人は面食らうと思うが、
javascriptは下のようにundefinedかもしれない変数をキーに
動的にオブジェクトを作成することができる。

bracket_example.js

// The name key may be undefined, but it is not an error.
// name keyがundefinedかもしれないがエラーにならない。
const helloObject = {
  x: 30,
  [name]: false

}

I think the programmer's intention is to assume that if name is undefined, then the name key itself does not exist or is false.
However, this is not allowed in most programming languages because it is a breeding ground for bugs. typescript does not allow it either. Therefore, the above syntax would result in a syntax error in typescript.

If you want to write it this way, you need to make sure that name is not undefined as shown below.

プログラマの意図としては、nameがundefinedならnameキー自体存在しない、またはfalseとなることを想定していると思う。
しかし、これはバグの温床になるせいか大抵のプログラミング言語では許されておらず、
typescriptでも当然許されていない。そのため上の書き方をするとtypescriptでは構文エラーになる。

この書き方をしたい場合nameが下記のようにundefinedでないことを保証する必要がある。

bracket_example.ts

// When adding properties to an object later in typescript, it is necessary to declare the object's type as shown below.
// typescriptで後からオブジェクトにプロパティを追加するときには下のようにオブジェクトの型を宣言する必要がある。
const helloObject:{ [key: string]: boolean | number } = {
  x: 30
}

if ( name !== undefined ) {
  // Since the condition for entering an if statement is that it is not undefined, it is guaranteed not to be undefined.
  // if文に入る条件がundefinedでないことであるため、undefinedでないことが保証されている。
  helloObject[name] = false;
}

const HelloClasses = classNames(cardClassesShape);

When to use this, for example, whether to take a class name as an argument in react as shown below.
This is useful when you don't know if the argument will be passed.

これをどのような時に使うかというと例えば下のようにreactでclass名を引数にとるかどうか。
引数が渡されるかわからない時に役に立つ。

bracket_example.ts

const classes = useStyles();

const helloClassesShape: { [key: string]: boolean } = {};

if (color !== undefined) {
  helloClassesShape[classes[color]] = true;
}

const helloClasses = classNames(helloClassesShape);

useState is null

components/HelloCompotents.js
const [element, setElement] = React.useState(null);

If null or undefined is used, it will be type any, and IntelliSense will not work.
There should be a specific type to use.
Use a generic to specify the type as shown below.

nullやundefinedを使うとany型になってしまうため、インテリセンスが効かなくなります。
使う型は決まっているはずなので、
下記のようにジェネリックを使って型を指定してください。

components/HelloCompotents.ts
const [element, setElement] = React.useState<HTMLElement | null>(null);

Value types such as string and number can be initialized like in golang, when initializing useState.
It is also a good idea to initialize them with an empty string and 0, respectively.

string型や、number型などの値型はgolangみたく、useStateの初期化時に
それぞれ空文字列,0で初期化するのもいいと思います。

components/HelloCompotents.ts

// Because the type is implicitly determined, completion becomes more effective.
// 暗黙的に型が決まるため、補完が効くようになります。
const [cnt, setCnt] = React.useState(0);
const [message, setMes] = React.useState('');

Discussion