LoginSignup
311
274

More than 1 year has passed since last update.

React + Typescript の現場で初心者からよくあった質問とか小技的なのを書いてく

Last updated at Posted at 2022-05-29

定数の Key のユニオン型を作る

const NAME = {
  HOGE: "hoge",
  FUGA: "fuga"
} as const;
keyof typeof NAME
// => "HOGE" | "FUGA"

定数の値のユニオン型を作る

typeof NAME[keyof typeof NAME]
// => "hoge" | "fuga"

ダウンキャストする

const { hoge, piyo } = router.query as {
  hoge: string;
  piyo: string;
};

強制ダウンキャストする

危険性ははらみますが・・・

const { hoge, piyo } = router.query as unknown as {
  hoge: number;
  piyo: number;
};

Material-UI の型を拡張する

基本的に 「コンポーネント名+ Props」という命名規則で提供されているのでそれを利用する。

type ExtendsProps = TextFieldProps & {
  hoge: number;
};

Material-UI のプロパティの型を利用する

TextField の型はTextFieldPropsで継承できるが、それの name プロパティを利用したい場合

type Props = {
  name: TextFieldProps["name"];
};

よく使うコメントの接頭語 アノテーションコメント(FIXME、TODO など)

VSCode では todo-tree などのプラグインを設定することでハイライトされ一覧で見ることが可能。

コメント 意味
FIXME: 不具合あるコード。絶対に修正するという強い意志を感じる。
TODO: やるべきこと。FIXME より弱い。修正するべき機能。
NOTE: 実装の意図やなぜこう書いたかを強調するときに書く。
HACK: リファクタリングしたい。
REVIEW: 見直しが必要である、または見てください。
WARNING: 注意してください。

Falsy とはなにか

false, undefined, null, NaN, 0 など真偽値で偽にあたる値のことをいう。

MDN にすべてが解説されているので参考にしてください。
Falsy (偽値)

// false, undefined, null, NaN, 0などのときは以下のエラーログを出力する
if (!hoge) {
  console.error("hoge がありません");
}
console.log(hoge);

突然な || ってなに?

よくある条件分岐の OR のやつ。
左辺が Falsy の場合、続けて右辺の式の評価をする特徴を利用している。
(下記コードの"HOGE"Truthy である)
つまり、hoge が Falsy の場合、"HOGE"が画面に出力させることができる。

const HogeComponent = ({ hoge }) => {
  return <div>{hoge || "HOGE"}</div>;
};
const a1 = false || "hoge"; // f || t returns "hoge"
const a2 = "hoge" || false; // t || f returns "hoge"

突然な && ってなに?

よくある条件分岐の AND のやつ。
左辺が Truthy の場合、続けて右辺の式の評価をする特徴を利用している。
つまり、loading が Truthy の場合 (ページをロード中である)、Loading コンポーネントが画面に出力する意図がある。

const HogeComponent = ({ loading, hoge }) => {
  return (
    <>
      {loading && <Loading />}
      <Typography>{hoge}</Typography>
    </>
  );
};

この ?. と ?? は何ですか?

オプショナルチェーン ?.
参照が nullish (null または undefined) の場合にエラーとなるのではなく、式が短絡され undefined が返される。

Null 合体演算子 ??
左辺が nullish の場合 右辺の値を値を返却し、それ以外の場合左辺を返却する。

  • user が undefined の場合は undefined を返却する
  • user に含まれる hoge というプロパティが null 又は undefined のとき "hoge"を表示する
const piyoList = userList?.map((user) => ({
  hoge: user?.hoge ?? "hoge",
  fuga: user?.fuga ?? "fuga",
  piyo: user?.piyo ?? "piyo",
}));

?? と || はどう使い分けるべきか?

|| 演算子は ?? 演算子の判定を含んでいるので混同して使用されがちである。
undefined || null の場合のみ限定的に判定したい場合は??演算子を利用したほうが、他者がコードを見た際に意図が汲み取れやすいというメリットがあり、状況によっては意図しない挙動をとると考えられる。

不都合な例

例えば 0 という数値をパラメタで渡す場合は || は適切ではない。(Falsy な値には 0 が含まれるため)

以下のように任意の幅を指定できるコンポーネントがあるとする。

const WidthComponent = ({ width }) => {
  return <div style={{ minWidth: width || "400px" }}>横幅をきめる</div>
};

このコンポーネントを呼び出す際に width に 0 を指定した場合は常に 400px が適応される。0 は Falsy であり、右辺の評価へ移るからである。

オプショナルチェーンを関数で使いたい

functionName?.() と記載することで可能。
また複数のオプショナルチェーンも当然併用することができる。

const productName = product?.getName?.();

これを使用することで以下のような冗長な記述を減らせる

const productName = product?.getName ? product.getName() : undefined;

オプショナルチェーンを配列で使いたい

const product = products?.[0]と記載することで可能。
配列インデックスの後にオプショナルチェーンをしたい場合は[]の直後に?を書く。

const user = userList?.[3]?.hoge ?? "HOGE"

上記を踏まえてプチクイズ

const userList = [
  {hoge:"hoge1",piyo:"piyo1"},
  {hoge:"hoge2",piyo:"piyo2"},
  {hoge:"hoge3",piyo:"piyo3"},
]
const user = userList?.[3]?.hoge ?? "HOGE"
console.log(user); // 何が出るかな?

文字列結合はテンプレートリテラルを使ったほうが良い説

現場にもよるが基本的に文字列の結合はテンプレートリテラルを使用したほうがスッキリするので良い。

const mergeString = (hoge: string, fuga: string, piyo: string) =>
  `${hoge}_${fuga}_${piyo}`;

上記のアロー関数の書き方に return がない

Arrow Function は波括弧を省略できる書き方があり、 return も不要である。
適当なキーを生成する際に使ったりしていた。

上記の関数をちゃんとスコープ書くと以下のようになる。

const mergeString = (hoge: string, fuga: string, piyo: string) => {
  return `${hoge}_${fuga}_${piyo}`;
};

...?

久保帯人先生の文節ではなくスプレッド構文のこと。

使用用途が非常に広くすべてを解説するのが面倒なので極めたい人は別記事を参照ください。
https://qiita.com/akisx/items/682a4283c13fe336c547

配列をマージする

const hoge = [1, 2, 3];
const fuga = [4, 5, 6];
const piyo = [...hoge, ...fuga]; // => [1,2,3,4,5,6]

オブジェクトを差分更新する

const defaultValue = {
  hoge: "hoge",
  fuga: "fuga",
  piyo: "piyo",
};

const inputValue = {
  hoge: "hogehoge",
  fuga: "fugafuga",
};

const result = { ...defaultValue, ...inputValue };
// => {hoge: "hogehoge", fuga: "fugafuga", piyo: "piyo"}

コンポーネントにパラメタをまとめて渡す

type HogeProps = {
  hoge: string;
  piyo: string;
};

export const Hoge: React.VFC<HogeProps> = (props) => {
  return (
    <>
      <ChildComponent {...props} />
    </>
  );
};

分割代入は別名でできる

戻り値の型が固定化されている Hooks などを同階層のコンポーネントで呼び出す際に使ったりする。
apollo client の FetchQuery を使うとき、これがよく出てくる。はず。

type Response = {
  loading:boolean;
  data: unknown;
}
const getResponse = ():Response => ({
  loading: true;
  data : {
    hoge: "hoge";
    fuga: "fuga";
  }
})

const {data, loading} = getResponse(); // 通常の分割代入
// 別名の分割代入
const {data: data2, loading: loading2} = getResponse()

分割代入はネストにも対応できる

分割代入はネストした方に対してもできる!
詳しい記事 → https://qiita.com/righteous/items/157e6f0e633c42dbe331

type APIResponse = {
  code: string;
  data: {
    hoge: string;
    fuga?: string;
    piyo?: string;
  }[];
};

const {
  code,
  data: [{ hoge, fuga, piyo }],
} = res; // res は APIResponse型とする

終わりに

ご指摘や、これが意味わかめんたいこだったというのがあればどしどしコメントください。

311
274
10

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
311
274