【備忘録】TypeScript: 型まとめ

プログラミング全般
スポンサーリンク

はじめに

TypeScriptの学習を始めたので、備忘録を残したいなと思いました。
あくまでメモなので、誤字脱字やコードの間違いなどもあるかもしれませんが、ご了承ください🙇‍♂️
今回は型編です!

型まとめ

ここからは各型についてのまとめメモになります!

string型

文字列型
'', "", で文字列になっている値を代入できる

let value: string = 'hoge'
value = ""
value = ``

number型

数値を入れられる型
不動小数点やマイナスの値も代入できる!

let value: number = 10
value = 1.11
value = -1.11

boolean型

true or falseしか代入できない

let value: boolean = true

object型

複数の値をキーバーリューで定義できる
値を,で繋いで定義する
object型で定義すると、あくまでオブジェクトであるdrinkにしかアクセスできない

const drink: object = {
  name: 'coffee',
  isHot: false,
}

// エラーになりアクセスできない
console.log(drink.name)

objectで型注釈すると、プロパティにアクセスできないので、基本は型注釈せずTypeScriptの型推論に任せるだけでも大丈夫そう
以下のように各キーにも型を定義することで、各キーにもアクセスできるようになる

const drink: {
  name: string;
  isHot: boolean;
} = {
  name: 'coffee',
  isHot: false,
}

// エラーにならない
console.log(drink.name)

array型

配列内の値にも型を定義することができる

const stringArray: string[] = ['hoge1', 'hoge2', 'hoge3']
const hoge1Value = stringArray[0]

// stringArray定義時に文字列しか入らないように型注釈しているので、String型のメソッドも使用することができる
hoge1Value.toUpperCase()

// 文字列しか入れることができないのでエラーになる
stringArray.push(100)

tuple型

簡単にいうと厳しい制限のかかった配列です
配列の中身に決まった複数の型の値しか代入したくない場合、tuple型で定義することで実装できます

例としては、飲み物の情報を格納した配列を定義したい場合、[名前, 温かいかどうか]だけの情報を持ちたいケースがあるとします
上記のようなケースでは、tuple型を使用することで不要な値が入らないようにすることができます!

let drink: [string, boolean] = ['オレンジジュース', false]

// 代入できる
drink[0] = 'アイスコーヒー'

// エラー: drink配列の0番目はstring型なので、numberを代入することはできない
drink[0] = 100
// エラー: tuple型で[string, boolean]の2つしか要素を定義していないので、値を追加することはできない
drink.push(100)

any型

なんでも代入できる型です
TypeScriptなのに、型の制限がゆるゆるになってしまうので、なるべくany型を使用しない方が良いです
他の変数で型を定義しているのに、any型は代入することができるので注意です!

// 全てエラーにならない
// 素のJavaScriptのような挙動になる
let value: any = true
value = 'hoge'
value = 100
value = {}
value.name = 'アイスコーヒー'
value = ['オレンジジュースは', 'あったかい']

// any型は他の変数に代入する場合でもエラーにならない
let hogeString: string = 'ほげです'
hogeString = value

unKnown型

any型とほぼ同じですが、少し厳しくなったunknown型というものがあります
unknownで定義した変数に代入するのはどんな型の値でも入れることができますが、他の型注釈のある変数に代入しようとするとエラーになります

let unKnownValue: unknown
let anyValue: any
let text: string

// any型と同じで代入する場合は自由
unKnownValue = 'hoge'
unKnownValue = 100
unKnownValue = true

anyValue = 'hoge'
anyValue = 100
anyValue = true

text = anyValue
// 型が決まっている値に代入しようとするとエラーになる
text = unKnownValue

ちなみにunknow型はany型と違い、if節でtypeofを使用し判定を行うと、判定結果の型として扱うことができます

// typeofでstringの場合にしか中を通らないのでstringとして扱うことができる
if (typeof unKnownValue === 'string') {
  unKnownValue.toUpperCase()
  // toFixedはnumber型の関数なのでエラーになる
  unKnownValue.toFixed()
}

if (typeof unKnownValue === 'number') {
// toUpperCaseはstring型の関数なのでエラーになる
  unKnownValue.toUpperCase()
  unKnownValue.toFixed()
}

// 型が特定できない場合はそのままunKnown型として扱われます
if (typeof unKnownValue !== 'string') {
  // unKnown型に存在しない値なのでエラー
  unKnownValue.toUpperCase()
  // unKnown型に存在しない値なのでエラー
  unKnownValue.toFixed()
}

enum(列挙型)

特定の値のみしか受け付けない型になります
例としてドリンクのサイズを定義したenumを用意しています
特定のケースなどを定数のように定義することができるので便利ですが、問題もあるので後述するunion型とliteral型を組み合わせてを使う方が推奨されているようです

enum DrinkSize {
  SMALL = 'SMALL',
  MEDIUM = 'MEDIUM',
  LARGE = 'LARGE',
}

const drink: {
  name: string;
  size: DrinkSize;
} = {
  name: 'オレンジジュース',
  size: DrinkSize.SMALL
}

drink.size = DrinkSize.LARGE
// enumで定義した値以外を代入することはできないのでエラーになる
drink.size = '大きいサイズだよ'

ちなみにenumの値を以下のように定義しない場合、上の値から0,1,2と勝手に代入される
ただ、enumの値を定義しない場合、問題もある

enum DrinkSize {
  SMALL,
  MEDIUM,
  LARGE,
}

const drink: {
  name: string;
  size: DrinkSize;
} = {
  name: 'オレンジジュース',
  size: DrinkSize.SMALL
}
drink.size = DrinkSize.LARGE
// enum定義していない値である100を代入してもエラーにならない
drink.size = 100

union型

数値と文字列のみを代入できる変数を作成したい場合などの、複数の型を使用する際、union型で実装することができます

let value: number | string = 10
// valueには数値の10が入っているのでstring型の関数は使用できない
// エラーになる
value.indexOf('す')

// union型でnumberとstringが代入されることを許容しているのでエラーにならない
value = '文字列です'
// valueには文字列が入っているのでエラーにならない
value.indexOf('す')

また、配列でも使用することができます!

let valueArray: (number | string)[] = [10, 'hoge', 999, '文字列です']

literal型

literal型は特定の決まった値のみを代入することができるようになる型になります
以下の例ではliteral型で'hoge'という文字列のみを代入することができるようにしています
文字列だけでなく、numberやbooleanでも同様です

let hogeValue: 'hoge' = 'hoge'

// 'hoge'しか代入できないので、以下は全てエラーになる
hogeValue = '文字列です'
hogeValue = 10
hogeValue = false

また、constで宣言した場合は自動的にliteral型が使用されます

// 上記の例と実質同じ
const hogeValue = 'hoge'

union型と組み合わせて、enumのような使用をすることもできます

let size: 'small' | 'medium' | 'large' = 'small'
size = 'medium'
// 型以外のものは代入できない
size = 'ほげほげ'

undefined型

TypeScriptではundefinedも型として扱うことができます

// どちらの変数も値はundefined
let value: undefined
let undefinedValue

value = undefinedValue
// 文字列を代入しようとしているのでエラーになる
value = 'ほげ'

ちなみにundefinedは値が代入されていないため、値がないものになります
変数を定義しただけだと、値が何も入っていないのでJavaScriptが勝手にundefinedを代入してくれています

// 以下のようにtypeofで型を調べると'undefined'が出力される
let undefinedValue
console.log(typeof undefinedValue)

void型

voidとは虚という意味もあり何も返さない型になります

const voidFunc = (): void => {
  console.log('この関数ではなにもreturnしていません')
} 
console.log(voidFunc())

// 以下出力結果
-> この関数ではなにもreturnしていません
-> undefined

returnで何も返していない時は上記のコードのように、JavaScriptの仕様でundefinedが返ってきますが、undefined型を使用するとエラーになります

// returnで何も返していない場合はvoidかanyしか使えないのでエラーになる
const voidFunc = (): undefined => {
  console.log('この関数ではなにもreturnしていません')
} 

ただreturnを書くと、undefined型を戻り値に指定してもエラーにならなくなります
また、voidも指定できます

const voidFunc = (): undefined => {
  console.log('この関数ではなにもreturnしていません')
  return ;
} 
const voidFunc = (): void => {
  console.log('この関数ではなにもreturnしていません')
  return ;
} 

どっちを使うかですが、基本的にTypeScriptが用意してくれているvoidです!undefined型は使用しない方が望ましいです
ただ、undefined型で返すことが元から決まっている場合は、指定した方がいい場合もあります

never型

neverには決してという意味があります
never型は決してなにも返さないということを型注釈する際に使用します
用途としては、何も返さない、つまり関数のエンドポイントへ到達しないことが事前にわかる場合に型注釈することができます

// エラーを投げるとその場で処理が止まりエンドポイントへ到達しないのでエラーにならない
const error = (message: string): never => {
  throw new Error(message)
}

// while (true)は処理が終わらずエンドポイントへ到達しないのでエラーにならない
const error2 = (message: string): never => {
  while (true) {

  }
}

// console.logの処理が終わるとエンドポイントへ到達するのでエラーになる
const error3 = (message: string): never => {
  console.log('ほげ')
}

null型

nullも型として扱うことができます

let nullValue: null = null
nullValue = null

// null型でなくnumberを代入しようとしているのでエラーになる
nullValue = 1

ちなみにnullをtypeofで判定しようとするとJavaScriptの仕様で"object"になります
nullを判定する場合は、型でなく値で見た方がいいかもしれません

console.log(typeof null)

出力結果-> "object"

型関連の学習メモ

型の解説とは別で型に関連したことも学んだのでメモを残しました。

型注釈・型推論

  • 型注釈
    • その変数にどんな値が代入可能かを指定できる機能
    • ざっくりした説明だと「この変数は〇〇型です!」と注釈を入れられる機能
    • メリットとして他の型の値が入ってくることを防ぐことができる, 変数のドキュメントになるなどがある
      // 型注釈
      let value: string = 'hoge'
  • 型推論
    • 型を書かなくても、コンパイラが自動で型を推測して理解してくれる機能
    • ざっくりした説明だと「この値だけどすでに1が入っているからnumber型なんじゃないの?」とコンパイラが推論してくれる
    • メリットとしてコーディング時の間違った値を代入してしまうなどのヒューマンエラーを防ぐ, 型推論を活用して型注釈の使用数を削減できるなどがある
      let value = 'hoge'
      // エラーが表示される
      // コンパイラが型を推論してくれているおかげ
      value = 21

関数の引数と戻り値の型を指定する

TypeScriptは他のメジャーな静的型付け言語と同様に関数にも型を指定することができます
以下の例で、引数と戻り値両方number型の関数を作成しています

// 引数と戻り値両方numberの関数
const sum = (num1: number, num2: number): number => {
  return num1 + num2
} 

sum(1, 2)

// 以下は両方エラーになる
const sum = (num1: number, num2: number): number => {
  // numberで返さないといけないのに、文字列を返すことになるのでえラー
  return num1 + num2 + 'ほげほげ'
} 

// 引数はnumberを求めているのに文字列を入れているのでえラー
sum('ほげ', 2)

typeエイリアスを使って、型を変数のように扱う

TypeScript独自の機能でtypeエイリアスというものがあります
union型などで、型の定義が長くなる複数の箇所で同じ型を使いまわしたい場合などで以下のように変数のように扱うことができます

// SizeTypeという
type SizeType = 'small' | 'medium' | 'large'
let size: SizeType = 'small'
size = 'medium'
// SizeTypeないで定義した型に沿っていない値を代入しているのでエラーになる
size = 'ほげほげ'

注意点ですが、typeを定義する場合元から存在している型名を使用することはできません

// string型は元から用意されているのでエラーになる
type string = 'ほげ' | 'ほげほげ' | 'ほげほげほげ'

余談ですが、typeエイリアスですが、tsからjsにコンパイルすると記述が消えるので、あくまでコードを書く際にえラーを吐いてくれるもののようです

関数にも型注釈が働く

関数に関数を代入する際も、元の関数の引数や戻り値の型を元にエラーを出してくれます

const sum = (num1: number, num2: number): number => {
  return num1 + num2
} 

const sum2: (n1: number, n2: number) => number = sum

// 元のsum関数の戻り値はnumberなので、戻り値の型がstringだとエラーになる
const sum3: (n1: number, n2: number) => string = sum
タイトルとURLをコピーしました