🗂

TypeScriptのイカれたメンバー (主要技術) 達を紹介していくぜ!!

2023/06/25に公開
8

はじめに

TypeScriptを勉強していて、使用する技術とそのサンプルのコードの一覧があれば便利だなぁ
と思ったので投稿することにしました。

対象読者

  • TypeScript初心者
  • TSをインストールしたけど挫折した人

前提条件

そもそもTypeScriptとはなにか?

TypeScriptとは、JavaScriptがベースとなっていて変数や引数なんかに対して型というものを付けることができる言語です。

型っていうのは、この変数には文字しか代入できないですよ~!!なんてな感じでデータの出入りを制限できるものになります。

変数や関数の後に「:」を付け、その後に任意の型を書けば完了です。これを書くだけで晴れてあなたもTypeScripterの一員です。

//mojiという変数に:を付け、string(文字列)を指定
let moji: string = 'Hello World!!'

TypeScriptでよく使われる奴ら

プリミティブな型たち

まずはプリミティブから伝えるのがベターなので紹介します。

なんだよ!! プリミティブ型って!!!!って思った方は安心してください。
要はTypeScriptで扱える基本的な型たちのことです。(文字列とか数値とか)

//文字列:string
let str: string = 'こんにちは';

//数値:number
let num: number = 123;

//でかい数値: bigint
let bignum: bigint = 1235467891234567n;

//真偽値:boolean
let bool: boolean = true;

//空な値:null
let n: null = null;

//未定義な値:undefined
let ud: undefined = undefined

//これ以外に同じ値のデータは無い!!(一意なデータ):symbol
let sym: symbol = symbol()

ユニオン型

型は1つの要素に対して複数の型をつけることもできます。それを可能にするのがユニオン型です。パイプ(こういうやつ⇒ | )で区切ることで宣言できます。

//文字列と数値を代入できる変数 ※es2020以降
let str_num: string | number

str_num = 'こんにちは'
console.log(str_num) // こんにちは

str_num = 123
console.log(str_num) // 123

リテラル型

文字列のみ受け入れるどころか、もうこのデータしか受け付けません!!みたいなこともできます。そういう時はリテラル型を使いましょう。

//Helloしか代入できない
let greet: 'Hello' = 'Hello'

配列型

配列も型として宣言できます。型名の後に[]を付けて宣言すると、その型しか挿入できない型が作成できます。
また、ユニオン型を使って複数の型が入る配列も作成できます。

//数値の配列
let nums: number[] = [1,2,3];

//文字列の型
let strs: string[] = ['a','b','c'];

//色々な型の配列
let some: (string | number | boolean)[] = [1,'Hello',true];

オブジェクト型

オブジェクトも型として宣言できます。オブジェクトの形式で1つのプロパティに対して自由に型を宣言できます。

//名前と年齢のオブジェクトを指定する型
let mydata: { name: string, age: number } = {
	name: 'Taro',
	age: 20
}

基本的にオブジェクト型に代入する値は宣言したプロパティの数だけデータを入れないとエラーになります。

いやいや、、、プロパティによってはデータ入れたくない場合もあるんだけど、、、

そういう場合はプロパティの後に「?」を付けましょう。そうすることで?を付けたプロパティだけはデータを入れなくてもエラーにはならなくなります。

//エラーになる...
let mydata: { name: string, age: number, profile: string } = {
	name: 'Taro',
	age: 20,
}

// ↓

//エラーにならない!!
let mydata: { name: string, age: number, profile?: string } = {
	name: 'Taro',
	age: 20,
}

型エイリアス

「オブジェクト型とかユニオン型って長くなって見づらいなぁ」って時は型エイリアスを使うとよいでしょう。型エイリアスは「type 任意の名前 = 型」の形式で宣言できます。

型エイリアスを使えば、長くなったオブジェクト型などを短い文字に変換することができます。

type ProfileData = {
	name: string,
	age: number,
	profile?: string
}

const myprofile: ProfileData = {
	name: 'Taro',
	age: 20,
	profile: 'こんちゃー!!!'
}

エイリアスは配列なんかにも指定できちゃいます。

type ProfileData = {
	name: string,
	age: number,
	profile?: string
}

const profiles: ProfileData[] = [
	{ name: 'Taro', age: 20, profile: 'こんちゃー!!!' },
	{ name: 'Jiro', age: 58, profile: '御座候' },
	{ name: 'Saburo', age: 2 }
]

エイリアスの中にエイリアスを指定なんかもできちゃいます。
これを利用してリテラル型を組み合わせると、より堅牢な型を定義することも可能です。

type UserName = string;
type UserAge = number;
type UserGender = 'men' | 'women' | 'other'; // リテラル型で性別データを指定

type UserType = {
	name: UserName,
	age: UserAge,
	gender: UserGender
}

const userData: UserType = {
	name: 'Taro',
	age: 21,
	gender: 'men'
}

interface

interfaceはtypeと似ていて型の定義をまとめることができます。
大きな違いとしてはクラスの型付けやオブジェクトの型付けでだけ使える点です。

//インターフェースの定義
interface UserInterface {
	name: UserName,
	age: UserAge,
	gender: UserGender
}

//profileプロパティを追加
interface UserInterface {
	profile: string,
}

関数の型定義

TypeScriptで関数を作成する際は、引数や戻り値にも型定義をする必要があります。
引数は引数の後に型を定義し、戻り値は引数のカッコの後に型を定義します。

//関数の定義
function sum(a: number, b: number): number{
	return a + b;
}

//アロー関数ならこんな感じ
const sum = (a: number, b: number): number => x + y;

//デフォルトの値も設定可能で、引数が渡らなくても計算可能になります。
function sum2(a: number, b: number = 1): number{
	return a + b;
}

console.log(sum2(5)) // 6

//戻り値が無い関数の場合はvoidを指定します。
const greet = (text: string): void => console.log(text)

関数の定義も冗長的になりがちなので、エイリアスで簡略化するのも良いでしょう。
以下のように宣言します。

//関数の型定義
type SumType = (a: number, b: number) => number

const sum: SumType = (a,b) => a + b;

ジェネリクス

なんかかっこいい名前...って思ったあなた。名前だけでなく機能もカッコいいです。

これは主に関数の定義の時に使用され、型を関数使用時に自由に決められるようになる機能です。

2つ関数があるけど、2つとも1個の引数の型以外はほぼ一緒の型なんだよなぁ、、、同じようなもの2つ書くのやだなぁ、、、

なーんて時に便利です。

//<>の中に型の情報が渡ってきます。
const arrGenerator = <T>(value: T, time: number): T[]{
	return new Array(time).fill(value) //配列をvalueのデータで埋め尽くす
}

console.log(arrGenerator<number>(1, 3)) //[1,1,1]
console.log(arrGenerator<string>('foo', 3)) //['foo','foo','foo']

コンポーネントの定義

Reactコンポーネントを定義するときはReact.FCを使いましょう。

//---------------------------------コンポーネント
const Hello: React.FC = () => {
	return <h1>Hello Workd!!</h1>
}
export default Hello

//---------------------------------コンポーネントを利用
import Hello from './Hello'

const App: React.FC = () => {
	return <Hello />
}
export default App

propsの定義

propsにも型を定義する必要があります。propsでは型エイリアスやジェネリクス、関数の定義で習った技術を利用すると良いでしょう。

//---------------------------------コンポーネント
//propsの型
type Props = {
	greet: string
}

//コンポーネント作成
const Hello: React.FC<Props> = (props) => {
	return <h1>Hello {props.greet}</h1>
}
export default Hello

//---------------------------------コンポーネント利用
import Hello from './Hello'

const App: React.FC = () => {
	return <Hello greet='World!!!'>
}
export default App

また、childrenを定義する場合はReact.ReactNodeを定義しましょう。

//---------------------------------コンポーネント
//propsの型
type Props = {
	greet: string,
	children: React.ReactNode
}

//コンポーネント作成
const Hello: React.FC<Props> = (props) => {
	return (
		<>
			<h1>Hello { props.greet }</h1>
			<div>{ props.children }</div>
		</>
	)
}
export default Hello

//---------------------------------コンポーネント利用
import Hello from './Hello'

const App: React.FC = () => {
	return <Hello greet='World!!!'>Its A My World!!!</Hello>
}
export default App //<h1>Hello World!!!</h1><div>Its A My World!!!</div>

関数を渡すことも可能です。

//---------------------------------コンポーネント
//propsの型
type Props = {
	func: () => void
}

//コンポーネント作成
const Btn: React.FC<Props> = (props) => {
	return <button onClick={ () => props.func }>ボタン</button>
}
export default Btn

//---------------------------------コンポーネント利用
import Btn from './Btn'

const App: React.FC = () => {
	const greet = () => console.log("Hello World!!!")
	return <Btn func={ greet } />
}
export default App

イベントの型定義

コンポーネント内でボタンのクリックイベントやselectタグのチェンジイベントの処理を分けて記述するときは、React専用のイベント型を定義する必要があります。

const App = () => {
    //クリックイベントの定義
    const handleClick = (event: React.MouseEvent<HTMLButtonElement,MouseEvent>) => {
        console.log("Hello World")
    }

    return (
        <>
            <button onClick={handleClick}>ボタン</button>
        </>
    )
}

クリックイベントの他にも様々なイベント型が存在します。

  onClick: (event: React.MouseEvent<HTMLInputElement>) => void // クリックイベント 
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void // チェンジイベント 
  onkeypress: (event: React.KeyboardEvent<HTMLInputElement>) => void //キーボードイベント 
  onBlur: (event: React.FocusEvent<HTMLInputElement>) => void // 要素のフォーカスが外れた時
  onFocus: (event: React.FocusEvent<HTMLInputElement>) => void // 要素のフォーカス時のイベント 
  onSubmit: (event: React.FormEvent<HTMLFormElement>) => void // formのsubmit時のイベント 

stateの型定義

Reactのstateを定義する際も型が必要になります。useStateの後にジェネリクスで型を指定します。

//stateの定義
const [ state, setState ] = useState<string>('Hello')

//型エイリアスを利用することもできます
type Users = {
	name: string,
	age: number
}

const [ users, setUsers ] = useState<Users[]>([
	{ name: 'Taro', age: 20 },
	{ name: 'Jiro', age: 17 }
])

おわりに

今回の記事は、勉強したてで作成したものになります。
もし記事の中で「ここ、ちげぇだろうが!!」とか「なんでこの機能についての記述がねぇんだ!!!」とかの不備があれば、どしどしコメントください。

GitHubで編集を提案

Discussion

まっきんとっしゅまっきんとっしゅ

誤)Typescript 、Javascript
正)TypeScript、JavaScript
ですね!
タイトルにもあったので気になっちゃいました笑

ERASERERASER

「関数の型定義」のセクションで出ている以下のコードですが、引数同士の間に , が入っておりません。

//デフォルトの値も設定可能で、引数が渡らなくても計算可能になります。
function sum2(a: number b: number = 1): number{
vincent.maverickvincent.maverick

また、typeと違ってプロパティの定義を追加することができます

type A = {...};
type B = {...};
type C = A & B;

とすることで追加できますよ。
その他にもジェネリックでいかようにも切り刻めますし、僕は interface 派ではなく type 派ですね、TypeScript 感満載やしw

vincent.maverickvincent.maverick

また、Childrenを定義する場合はReact.ReactNodeを定義しましょう。
Childrenとは、呼び出したコンポーネント内で記述した内容をそのままpropsに渡せるReact専用の名称です。

Chirdren と children は別物ですよ。

こちらの文脈から推測するに、後者の小文字表記が意図するところと一致しますね。

全体的に?な部分が散見されますが、最初は誰もが初心者。
求道心を以て精進されたし!
応援してます

dk@個人開発してみたいdk@個人開発してみたい

これまた不勉強でした、、、
Childrenはchildrenを操作するための関数群だったのですね!

応援ありがとうございます!
精進に励み、頑張ります!