【TypeScript】いろんな型定義を調べてみた
概要
最近、React×TypeScriptの案件であったけど、型を指定する際のパターンをメモ。
特にもReactの場合って通常のstring
型とか以外にもある訳で。
ネットで検索していろいろ調べてたので忘備録としてメモ。
Propsに型を定義する
関数コンポーネントの引数Propsの型を定義するには、次のようにします。
propsで受け取る引数がひとつの場合
よくprops
で値を受けとる先に分割代入をすることがあるが、その型指定の方法。
//直接指定する
const App=({title}:{title:string})=>{}
//型エイリアス
type Props={title:string}
const App=({title}:Props)=>{}
型を直接指定する方法と型エイリアスを使う方法。
propsで受け取る引数が複数の場合
複数の場合は、直接型指定するより型エイリアスの方が良い。
//型エイリアス
type Props={
title:string,
num:number,
bool:boolean
}
const App=({title,name,bool}:Props)=>{}
childenを型指定する場合
children
はコンポーネントタグで囲った場合にどこに表示させるか指定する際に利用する。
children
はJSX要素を受けとる場合にReactNodeを指定して、単純に文字列だけの場合などはその型を指定する。
ReactNodeは下記のようにUnion型で指定されてる。
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
実際は以下のような感じ。
//コンポーネント
const Contents=({children}:{children:React.ReactNode})=>{
return(
<div>
<p>ここはContestsコンポーネント</p>
{children}
</div>
)
}
//呼び出す
const App=()=>{
return(
<div>
<p>ここは呼び出し元</p>
<Contents>
ここに内容を表示
</Contents>
</div>
)
}
文字列だけの場合
//コンポーネント
const Button=({children}:{children:string})=>{
return(
<button>{children}</button>
)
}
//呼び出す
const App=()=>{
return(
<div>
<p>ここは呼び出し元</p>
<Button>クリック</Button>
</div>
)
}
propsに渡す関数がある場合
関数などを親コンポーネントから渡す場合もあるので、その型の定義方法。
型エイリアスで書いた方が見通し良いと思うので型エイリアス。
引数や戻り値ありの場合もちゃんと記述しないといけない。
//引数や戻り値がある場合は以下
type Props={
sampleFunc:(text:string)=>string; //引数、戻り値がstring型
children:React.ReactNode:
}
//戻り値や引数がない場合は以下
type Props={
sampleFunc:()=>void; //戻り値がない場合はvoid
children:React.ReactNode:
}
const BtnComp=({sampleFunc,children}:Props)=>{
return(
<>
<button onClick={()=> alert(returnFc("テスト"))}>{children}</button>
</>
)
}
//呼び出す
const App=()=>{
//BtnCompに渡す関数
const sampleFunc = (text: string) => "出力:" + text;
return(
<div>
<p>ここは呼び出し元</p>
<BtnComp sampleFunc={sampleFunc}>アラート</BtnComp>
</div>
)
}
「?」で存在しない値を許容する
型を指定する際に、ある値がなくても問題ないという事を表すため為に「?(はてな)」をつける事ができる。これはundefined
の可能性もあるので、それを許容するという意味にもなる。
type Props={
name:string,
email?:string
}
const Contents=({name,email}:Props)=>{
return(
<div>
<p>私の名前は{name}です。</p>
{email && (
<p>email:{email}</p>
)}
</div>
)
}
上記の例でいうと、name
は必須だけどもemail?:string
となっているのでemail
に関してはundefined
を許容しているという事になる。
その場合、email
の型はstring | undefined
というユニオン型になる。
ただしemail
の場合は、単純に出力しようとすると値が存在しない(undefined
)の可能性もあるので、&&条件で存在しているか確認してから出力する。
デフォルト値を設定しておく
上記のように値がstring | undefined
を許容していても値が無かった場合の値を決めておきたい時に以下のように指定もいい。
仮にname
の値もstring | undefined
を許容して初期値を設定する。
type Props={
name?:string,
email?:string
}
const Contents=({name="ゲスト",email}:Props)=>{
return(
<div>
<p>私の名前は{name}です。</p>
{email && (
<p>email:{email}</p>
)}
</div>
)
}
上記にようにname
の値がない場合は、「ゲスト」の値が入る。
ユニオン型についての注意点 - 戻り値
string | undefined
で許容したとしても、関数で処理した結果を戻す場合に気を付けておいた方がいいと思った事。
例えば、以下の例はエラーになる。
const sampleFunc=(name?:string)=>{
return name;
}
const resultName:string=sampleFunc();
なぜエラーになるかというと、string | undefined のユニオン型が定義されているのに戻り値で受ける変数が文字列(string)型のためエラーになる
ちなみのlocalStorage.getItem()
の場合もエラーがでました。
const maybeUserId: string | null = localStorage.getItem("userId");
const userId: string = maybeUserId; // nullかもしれないので、代入できない。
以下のようなエラーがでる。
解決策としては条件分岐や!(感嘆符)で対処する
localStorage.getItem()
のような元からある場合はif文や&&条件といった条件分岐、
自作関数なら「!(感嘆符)」などで対処。
//条件分岐
const maybeUserId: string | null = localStorage.getItem("userId");
if (typeof maybeUserId === "string") { //文字列型かチェック
const userId: string = maybeUserId;
}
//感嘆符
const sampleFunc=(name?:string)=>{
return name!;
}
const resultName:string=sampleFunc();
感嘆符に関しては参考にしたブログの引用ですが、下記の説明でした。
name?の型は暗黙的に string | undefined のユニオン型が定義されているので、文字列型あ>る変数resutNameの型と一致しない訳エラーになります。
単純にresutNameの型をstring | undefinedにすれば良さそうですが、他にも戻り値で返す
nameの後ろに「!」(感嘆符)をつけることでもエラーが解消します。
多分ですが、undefinedでないことを宣言しているので、文字列型として処理されているのだ > と思います。
配列関連
配列の指定方法もいろいろあるのでチェックしてみた。
まずは型の後ろに配列の[]
を付ける。
const strArr=string[] =["文字列1","文字列2"]; //文字列型の配列
const numArr=number[]=[1,2,3]; //数字型の配列
//ユニオン型で複数の型の配列も可能
const arrStrNum=(string | number)[] = ["文字列",1];
ジェネリクス型で定義
ジェネリクス型でも指定できる。Array<型>
型で定義する。
const strArr=Array<string> =["文字列1","文字列2"]; //文字列型の配列
const numArr=Array<number>=[1,2,3]; //数字型の配列
//ユニオン型で複数の型の配列も可能
const arrStrNum=Array<string | number>[] = ["文字列",1];
配列の中にオブジェクトがある場合
よくデータ取ってくる際に、配列の中にオブジェクトがあったりするので、その場合の型の指定方法。こちらも通常の配列と同様に2種類の指定方法。
type PersonalInfo={
name:string,
age:number,
gender:string
}
const Persons = PersonalInfo[]=[
{name:"名前",age:25,gender:"男"},
{name:"花子",age:22,gender:"女"},
]
//ジェネリクス型だと下記
const Persons = Array<PersonalInfo>=[
{name:"名前",age:25,gender:"男"},
{name:"花子",age:22,gender:"女"},
]
Event関連
クリックイベントなど、Reactだと自動的にany
型になっていたりする。
const onClick = (event: any) => {
//処理
};
イベントにはchange
イベントやfocus
イベントなど色々あるんですが、以下のようなイベントの型がある。typeにまとめてあります。
const onClick = (e: React.MouseEvent<HTMLInputElement>) => {
}
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
}
const onkeypress = (e: React.KeyboardEvent<HTMLInputElement>) => {
}
const onBlur = (e: React.FocusEvent<HTMLInputElement>) => {
}
const onFocus = (e: React.FocusEvent<HTMLInputElement>) => {
}
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
}
const onClickDiv = (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
}
const onClickButton = (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
}
VScode(Visual Studio Code)を利用している場合は、マウスオーバーすればイベントの型を表示してくれます。
マウスオーバーしたらそれをコピーして、以下のようにすればいいかと。
const onClickhandler=(e: React.MouseEvent<HTMLButtonElement, MouseEvent>)=>{
//処理
}
return (
<div className="App">
<button onClick={(e)=>onClickhandler(e)}>クリック</button>
</div>
);
}
useState関連
ReactHooksのuseState
に関しては、useStateフックでは初期値を与えれば状態変数の型を推論してくれますが、あまり好ましくないよう。
型推論
const [name, setName] = useState("") // string型
const [count, setCount] = useState(0) // number型
ジェネリクス型
useState
は基本的にはジェネリクス型で対応した方がいい。
const [name, setName] = useState<string>("") // string型
const [count, setCount] = useState<number>(0) // number型
const [isChecked, setIsChecked] = useState<boolean>(false) // boolean型
配列やオブジェクトが含まれる場合
よくjsonからデータを取ってくると大抵はオブジェクト型だったりしてそれを配列で受け取ったりするのが多い。そのような場合は以下のようにする。
例えばユーザー情報を取ってくる場合など。
type User={
id:number
name:string,
gender:string
}
const [user, setUser] = useState<User[]>([{id:0,name:"名前","男"}])
まとめ
下記のサイトを参考にさせていただきました。
Discussion