# useStateの型、Dispatch<SetStateAction<T>> についてとジェネリック型

Table of Contents

useStateの型

useStateの状態管理関数をPropsで渡すとき、受け取る側は

Dispatch<SetStateAction<T>>;

という方で受け取ることになる。

ジェネリクスのメリットがいまいち

関係ないけどずっと気になっていた「ジェネリクスのメリットがいまいちピンとこない件」について、ついでに調べてみることにした。

例えば、

// 文字列を入力し、文字列を出力する関数
const returnText = (input: string): string => {
return input;
};
// 数値を入力し、数値を出力する関数
const returnNumber = (input: number): number => {
return input;
};
console.log(returnText("hello world"), "returnText");
console.log(returnNumber(0), "returnNumber");

という関数が存在した時、

const returnTextOrNumber = (input: string | number): string | number => {
return input;
};
console.log(returnTextOrNumber("hello world"), "returnTextOrNumber");
console.log(returnTextOrNumber(0), "returnTextOrNumber");

こんな感じにまとめたくなる。

これをジェネリック型にすると、

const returnTextOrNumberGeneric = <T extends string | number>(input: T): T => {
return input;
};

こんな感じになる。

型ガードが必要

同じように感じるけど、returnTextOrNumberの場合は、

const a: string | number = returnTextOrNumber("hello world");
const b: string | number = returnTextOrNumber(0);
console.log(a.length);
// Property 'length' does not exist on type 'string | number'.
// Property 'length' does not exist on type 'number'
console.log(b + 1);
// Operator '+' cannot be applied to types 'string | number' and 'number'.

stringnumberのどちらが返ってくる確定していないので、コンパイルエラーが出る。

実行するためには

if (typeof a === "string") {
console.log(a.length);
}
if (typeof b === "number") {
console.log(b + 1);
}

のように型ガードする必要がある。

コンパイラーをだませる

const b: string | number = returnTextOrNumber(0) as string;
console.log(b.length);

bは0なのでlengthが存在しないが、as stringで強制的に文字列とコンパイラーと認識させられる。

これはコード的負の遺産になる。

ジェネリック型は堅牢でコード量が少ない

対照的にジェネリック型であるreturnTextOrNumberGeneric の場合は、

const a = returnTextOrNumberGeneric<string>("hello world");
const b = returnTextOrNumberGeneric<number>(0);
console.log(a.length);
console.log(b + 1);

関数実行時に入出力共に型を指定し確定できるので、コンパイルエラーがでない。

また

const b = returnTextOrNumberGeneric<number>(0) as string;
// Conversion of type 'number' to type 'string' may be a mistake because neither type sufficiently overlaps with the other. If this // was intentional, convert the expression to 'unknown' first.(2352)

強制的に異なる方でコンパイラーを納得させようとしても不可能になり、堅牢制が向上した。

実際に整理してみるとジェネリック型の恩恵がよくわかった。

My avatar

Thanks for reading my blog post! Feel free to check out my other posts or contact me via the social links in the footer.


More Posts

Comments