説明が非常にわかりやすく、レビュー時などにのコメントでも使えそうなものが多かったのでオススメです。
自分用にメモを残します。
「_」区切りの数値リテラル
使う場面は少ないかもしれませんが、こういう書き方があるのかと。
TypeScript独自機能ではなく、序盤はこういったECMAScriptの解説も充実。
const million = 1_000_000;
console.log(million) // 1000000
BigInt
使ったことなかったので、知らなかった。
const bignum: bigint = (123n + 456n)
console.log(bignum) // 579n
null or undefined
書籍でも解説はあったが、調べると以下の記事がより分かりやすかった。
結論としてはundefinedを使う。
typeof undefined; // "undefined"
typeof null; // "object"
structuredClone
lodashのmergeの代わりになるもの。
主要ブラウザはほぼ対応。
Node.js では 17.0.0 から、Deno では 1.14 以降、対応予定
type or interface
(型の)typeofをいつ使うか
基本的にはtypeで明示的に型宣言をする。
以下のようにすることで定数と型の管理が1ヶ所になる。
const commandList = ['attack', 'defend', 'run'] as const
type Command = typeof commandList[number] // type Command = ['attack', 'defend', 'run']
オブジェクトリテラルを返すアロー関数の省略記法
たしかにこう書けるなと。
type RtnObj = {
bmi: number
}
const calcBmi = ({ height, wight }: Human): RtnObj => ({ bmi: weight / height ** 2 })
ただ、returnありのほうが多くの人が見慣れていて読みやすいと思う。
const calcBmi1 = ({ height, wight }: Human): RtnObj => ({
bmi: weight / height ** 2,
xxx: 123,
})
const calcBmi2 = ({ height, wight }: Human): RtnObj => {
return {
bmi: weight / height ** 2,
xxx: 123,
}
}
クラス型ではなく、あくまでオブジェクト。
class User {
name = ''
age = 0;
isAdult(): boolean {
return this.age >= 20
}
}
const user: User = new User()
console.log(user.name)
const user2: User = {
name: "hey",
age: 15,
isAdult: () => true
}
console.log(user2.name)
typeofによる絞り込み
const validate = (value: unknown): string => {
if(typeof value === 'string') {
return value
}
return "";
}
ユーザー定義型ガード
validate関数のような何が入っていくるか分からないものはunknownを使う。
const validate = (value: unknown): string => {
if(isString(value)) {
return value
}
return "";
}
// const isString = (v: unknown): boolean => typeof v === 'string'
const isString = (v: unknown): v is string => typeof v === 'string'
unknowにするとプロパティのチェックができずエラーになるのでこっちはanyにする。
type Human = {
name: string
age: number
}
const isHuman = (v: any): v is Human => {
if (v == null) return false
return typeof v.name === 'string' && v.age === 'number'
}
const validate = (value: unknown): Human => {
if(isHuman(value)) {
return value
}
}
Template Literal Types と ユーザー定義型ガード と 正規表現 を使ってEmail型を検証してみる
type Email = `${string}@${string}`
const email: Email = 'test@test.com'
const regex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
const isEmail = (v: string): v is Email => typeof v === 'string' && regex.test(v)
switch と if
switchがいいケース。
type Animal = {
tag: 'animal'
}
type Human = {
tag: 'human'
name: string
}
type Robot = {
tag: 'robot'
name: string
}
type User = Animal | Human | Robot
// if文の場合、全て網羅してもundefinedが返る可能性があるとエラーがでる
function getUserName1(user: User): string {
if(user.tag === 'human') {
return user.name
}
if(user.tag === 'animal') {
return '名無し'
}
if(user.tag === 'robot') {
return user.name
}
}
// switchの場合は「すべて網羅した」と認めてもらえる。defaultは書かない。
function getUserName2(user: User): string {
switch(user.tag) {
case 'human':
return user.name
case 'animal':
return '名無し'
case 'robot':
return user.name
}
}
getUserName1({ tag: 'robot', name: 'RX-123' })
getUserName2({ tag: 'robot', name: 'RX-123' })
組み込み型のPartialを見る
in keyof を使ってオプショナルにしていると。
type Partial<T> = {
[P in keyof T]?: T[P];
};
値、型の変換の例
// 3つの文字列をもつユニオン型
type Fruit = "apple" | "orange" | "strawberry";
// mapped typesにより「appleというプロパティが型numberを持ち、...strawberryというプロパティが型numberを持つオブジェクト型」
type FruitNumbers = {
[P in Fruit]: number
}
// FruitNumbers型のオブジェクトリテラルを作成
const numbers: FruitNumbers = {
apple: 3,
orange: 10,
strawberry: 20,
}
// keyof typeofを使って、オブジェクトリテラルから3つの文字列をもつユニオン型を生成
type FruitKey1 = keyof typeof numbers;
// keyofを使ってFruitNumbers型からら3つの文字列をもつユニオン型を生成
type FruitKey2 = keyof FruitNumbers;
const fruit1: FruitKey1 = 'orange'
const fruit2: FruitKey2 = 'apple'
// FruitNumbersからFruitStringを作成
type FruitString = {
[P in keyof FruitNumbers]: string
}
// FruitString型のオブジェクトリテラルを作成
const strings: FruitString = {
apple: 'りんご',
orange: 'みかん',
strawberry: 'いちご',
}