1
0

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.

typescript 型のお話 Record

Posted at

はじめに

Next.jsのプロジェクトを実装していた時のこと。
ちょっとしたコンポーネントを作りたくて、muiを使って実装しようとしたら引っかかってしまったところのお話

引っかかった点

引数によってサイズの変わるButtonコンポーネントが作りたかった。

hoge.ts
import { Button, Typography } from "@mui/material";
import Image from "next/image";
type HogeButtonProps = {
    text: string;
    size: "small" | "medium" | "large";
};
const size2int = {
    small: 24,
    medium: 36,
    large: 38,
};
const size2captionSize =
    {
        small: "h6",
        medium: "h5",
        large: "h4",
    };
export const HogeButton = ({ size, text }: HogeButtonProps) => {
    return (
        <Button>
            <Image
                src="/hoge.svg"
                width={size2int[size]}
                height={size2int[size]}
                alt="hoge"
            />
            <Typography ml={2} variant={size2captionSize[size]}>
                text
            </Typography>
        </Button>
    );
};

HogeButtonには引数としてtextsizeが渡せる。
textはボタンの文字にsizeはボタンの文字の大きさ、画像の大きさに関係する引数である。(割愛しているが実際はもう少し複雑な実装)

この時Typographyコンポーネントのvariantに以下のエラーが出ていた

    Type 'string' is not assignable to type '"h6" | "h5" | "h4" | "button" | 
"caption" | "h1" | "h2" | "h3" | "inherit" | "subtitle1" | "subtitle2" | "body1" 
| "body2" | "overline" | undefined'.
  Overload 2 of 2, '(props: DefaultComponentProps<TypographyTypeMap<{}, 
"span">>): Element | null', gave the following error.
    Type 'string' is not assignable to type '"h6" | "h5" | "h4" | "button" | 
"caption" | "h1" | "h2" | "h3" | "inherit" | "subtitle1" | "subtitle2" | "body1" 

| "body2" | "overline" | undefined'.ts(2769)

ようはvariantに入れる値の型が違うよっていう話である。
size2captionSizeの返り値はstringである。
ので一見大丈夫なように見えるが、muiTypographyvariantが要求するのはh1 h2 h3 ...といったある一定の文字しか許さない型なのである。

解決策

じゃあどうするのか、size2captionSizevaluemuiTypographyvariantに一致するようにすればいい。
といってもそんなやり方など私は知らない。
サバイバルTypeScriptを探してやっと見つけた型Recordである。

Recordとは

RecordはプロパティのキーがKeysであり、プロパティの値がTypeであるオブジェクト型を作るユーティリティ型です。

引用:サバイバルTypescript Record

つまりobjectkeyvalueに型がつけれるよという型です。
今回ほしいものにぴったりでした。

てことでいかが解決したコードです。

hoge.ts
import { 
    Button, 
    Typography, 
+   TypographyTypeMap 
} from "@mui/material";
import Image from "next/image";
type HogeButtonProps = {
    text: string;
    size: "small" | "medium" | "large";
};
const size2int = {
    small: 24,
    medium: 36,
    large: 38,
};
+const size2captionSize: Record<string, TypographyTypeMap["props"]["variant"]> =
    {
        small: "h6",
        medium: "h5",
        large: "h4",
    };
export const HogeButton = ({ size, text }: HogeButtonProps) => {
    return (
        <Button>
            <Image
                src="/hoge.svg"
                width={size2int[size]}
                height={size2int[size]}
                alt="hoge"
            />
            <Typography ml={2} variant={size2captionSize[size]}>
                text
            </Typography>
        </Button>
    );
};

TypographyTypeMap["props"]["variant"]というのはmuiTypographyvariantの型です。
これでsize2captionSizekeystringvalueypographyTypeMap["props"]["variant"]をとるオブジェクトとなりました。
エラーも出なくなりました。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?