🎄
TypeScript一人カレンダー 2022/2024 目次と索引 記号・A-N
こんにちは、クレスウェア株式会社の奥野賢太郎 (@okunokentaro) です。本記事は『TypeScript 一人 Advent Calendar 2022』および『TypeScript 一人 Advent Calendar 2024』(TypeScript一人カレンダー) 全50記事の目次と索引ページです。
- https://qiita.com/advent-calendar/2022/okunokentaro-ts
- https://qiita.com/advent-calendar/2024/okunokentaro-ts
本アドベントカレンダー内の各記事では、2024年12月、TypeScript 5.7, Next.js 14.x, Valibot 0.42の時点で解説しています。本アドベントカレンダーのすべての記事は、TypeScript初心者を脱し始めてもっと活用していきたいと願う読者層に向けていますので、最低限の前提は省略して記述しています。
目次
シーズン1
第1部 Conditional Types
-
1日目
ReturnType<T>
- Utility Types
ReturnType<T>
- どんなときに便利?
- 例1
- 例2
- 注意点
-
2日目
Awaited<T>
Awaited<T>
- どんなときに便利?
- 例1
- 例2
-
3日目
infer
と実例UnArray<T>
infer
-
ReturnType<T>
を読んでみる-
extends
がたくさん出てきて難しい?
-
- 実例
UnArray<T>
-
4日目 実例
runRenderHook()
- テストでちょっと困る型の扱い
- うーん?テストは書けたけど
-
runRenderHook()
- 戻り型アノテーションについて注意
-
5日目
Parameters<T>
,ConstructorParameters<T>
-
Parameters<T>
- Labeled Tuple Elements
- 得た型の使い方
- Indexed Access Types
- どんなときに便利?
ConstructorParameters<T>
-
第2部 Mapped Types
-
6日目
Pick<T, K>
-
Pick<T, K>
- keyof Type Operator
- どう使う?
- 例1
- 例2
-
-
7日目
Omit<T, K>
Omit<T, K>
- どう使う?
- 例
-
Pick<T, K>
との使い分け
-
8日目
Extract<T, U>
とExclude<T, U>
-
Extract<T, U>
- 業務でよく使う例1
- 業務でよく使う例2
Exclude<T, U>
-
-
9日目 Mapped Typesを活用する
- Mapped Types
- どうやって定義する?
- Template Literal Types
-
Pick<T, K>
の中身をみてみる
- Mapped Types
-
10日目
readonly
とReadonlyArray<T>
readonly
-
readonlyプロパティ
-
class
の場合の扱い
-
-
readonly
配列- 型の書き方
- 予約語ではない
- いつ使う?
- 余談
- Change Array by copy
- Records & Tuples
-
11日目 Mapping Modifiersと実例
Writable<T, K>
- テストでちょっと困る型の扱い2
Writable<T, K>
-
12日目
Partial<T>
Partial<T>
-
Omit<T, K>
と異なる点- プロパティ定義なし
- Optionalなプロパティ
-
T | undefined
のUnion
-
HasProperty
について理解する
-
13日目 実例
RecursivePartial<T>
-
Partial<T>
を活用する瞬間 -
RecursivePartial<T>
- なにをやっているか
- 再帰を活用しよう
-
-
14日目
Required<T>
,Readonly<T>
Required<T>
Readonly<T>
- いつ使う?
-
15日目
object
とRecord<K, T>
-
Record<K, T>
- プロパティとして指定しうる値の型
-
undefined
リスクに注意
- 縁の下の力持ち
- 任意のオブジェクト
- プロパティをひとつも含まないオブジェクト
- 業務ではあまり使わない
-
-
16日目
intrinsic
とTemplate Literal Typesintrinsic
- Intrinsic String Manipulation Types
- 業務ではどう使う?
- Template Literal Types における infer の挙動
- camelCaseからsnake_caseに変換する型を作る
- TypeScriptはチューリング完全
第3部 Assertion Types
-
17日目
NonNullable<T>
と実例assertExists()
NonNullable<T>
- nullの可能性を除去する実装
- コンポーネント内でNullableな変数を扱うハンドラ
- 雑なnull逃し
- 例外を投げるように変更
- Assertion Functions
assertExists()
exists()
- コンポーネントのハンドラを短く書く
- 嘘をつけてしまうため注意
-
Array.prototype.filter()
でのちょっと便利な書き方
-
18日目 Branded Typesを導入してみる
- Nominal TypingとStructural Typing
- Type Alias
- Nominal Typing Likeなclass
- Branded Types
- Branded Types が解決したこと
-
19日目 実例
FilledString
,UserId
- Branded Typesの改良
- Type Assertionsが使えるときと、使えないとき
- Type Assertionsが危険である状況
- Assertion Functionsを採用する
-
assertString()
とasString()
FilledString
- アレンジした
Brand<K, T>
で宣言するUserId
- Branded Typesの改良
-
20日目 String Literal Typesと
as const
enum
- String Literal TypesとUnion Types
-
isSuit()
関数を実装する- 定数を先に宣言しておくリファクタリング
- 定数から型定義を作りたい
as const
コラム
-
21日目
if
文とswitch
文は使い分ける?- ちょっとした疑問
- Narrowingとエディタの挙動
- Visual Studio Code
-
if
文 -
switch
文
-
- WebStorm
-
if
文 -
switch
文
-
- 結論、やはりどっちでもいい
-
22日目 実例
mapOrElse()
- ジェネリクスはどういうときに使うか
mapOrElse()
- 身近なジェネリクスを扱う例
-
23日目 実例
extends Error
- TypeScriptプログラミングにおけるエラー
- ECMAScript処理系で実行されるという事実からは逃れることができない
- 完璧なフォローはコストが高い
-
catch
ブロック内での型付け -
catch
のerr
はError
型インスタンスとは限らない - 暗黙的に
err: Error
であると扱えない理由 - 実例
extends Error
- Errorを継承しないクラスはおすすめしない
-
24日目 実例 再帰型定義と
RGBA
- 過去の頑張りを話します
- TypeScriptの限界
-
RGBA
改 - TypeScript 5.0
第4部 Conditional Types, Mapped Types, Assertion Typesを組み合わせる
-
25日目 実例
assertMatchedType()
- TypeScriptの集大成
- 不確実な環境での安心の獲得
- 不整合は常に起こりうる
- 防御的プログラミングと契約による設計
- 不整合はなぜ起こったか
- 内部起因か外部起因か
-
unknown
型を扱った信頼できる仕組みづくり- Assertion Functions
-
unknown
型を採用する欠点 - 開発のモチベーション
-
assertMatchedType()
の実装- 型のユニットテスト
- 登り方を検討する
RemoveNeverProperties<T>
Escape<T>
UnionToUnionTuple<T>
-
isMatchedType<T>()
のランタイム実装 assertMatchedType()
- 完成
- 総括
シーズン2
第1部 Valibot を前提とした実装の変化
-
1日目 Valibotのご紹介
- Valibot
- Valibot と Zod のコード比較
- Valibot を使ってバリデーション処理を実行する
-
2日目 Valibotで実践するBranded types
- Branded typesとは
- Branded typesの浸透とValibot
-
3日目 応用編 Valid branded types
- さらに一歩踏み込むValid branded types
-
FilledString
型をValibotで実現する - 1文字以上であることが必須な応用型の定義
- 時間型もより厳密に
- 2年で変わったTypeScriptエコシステム
-
- さらに一歩踏み込むValid branded types
-
4日目 文字列や配列の最大長が決まっていないときの対策
- スキーマ記述と不明確な上限値の問題
- 業務上「最大値未定」が頻出する理由
- 「最大値未定」を明示するアプローチ
- なぜECMAScriptの限界値を参考にするのか
- まとめ
-
5日目 実例
neverUsed()
,$()
- Valibot利用上のさらなる工夫
-
neverUsed()
: 使用しないプロパティを明示する -
$()
:strictObject()
のエイリアスで可読性向上 - エイリアス導入の是非
第2部 ユーティリティ集から学ぶ
-
6日目
DeepReadonly<T>
-
DeepReadonly
を求める理由 - ts-essentialsの
DeepReadonly
を導入する - ライブラリ導入時に考えたいこと
- まとめ
-
-
7日目
StrictOmit<T, K>
-
Omit<T, K>
の弱点 -
StrictOmit
型で厳密なエラーチェック - TypeScript標準ユーティリティの設計意図と実務での選択
-
-
8日目 実例
ExtractKeyOf
-
Extract
の弱点とキー操作 -
ExtractKeyOf<T, K>
を自作 - Rustから学んだ「エラーは学びの源」
- 自作型作成の指針
-
-
9日目 実例
is()
- typeプロパティを持つオブジェクトとDiscriminated union
- User-defined Type Guard量産からの卒業
- 汎用的な
is()
関数による絞り込み - なぜ
is()
が有効なのか - まとめ
-
10日目 実例
hooksTestingTools()
-
runRenderHook()
につきまとう副作用の取り扱いとトラブル -
hooksTestingToolsFactory()
の導入 - 実務発のニーズとそれを解決させる工夫の匙加減
-
-
13日目 実例
mustFind()
-
strictNullChecks
の便利さと不便さ -
mustFind()
の実装例 - オーバーロードでType predicate signatureにも対応する
- テストコードでの確認
- TypeScriptテクニックを実務に活かす
-
-
14日目 Vitest
test-d.ts
で複雑な型をテストする- 型定義にもテストを書く時代
- Vitestで型定義をテストする
-「型パズル」と呼ばせないために
第3部 TypeScript の新機能を学ぶ
-
11日目 noUncheckedIndexedAccess
- 配列アクセス時の
undefined
リスクを検出するオプション - 無効時と有効時の挙動を比較
-
undefined
チェックの手間を惜しまない -
as const
も併用する - 今すぐオプションの有効化を検討しよう
- 配列アクセス時の
-
12日目 satisfies
-
satisfies
で型適合性を柔軟に示す - 変数型アノテーションと
as const
の組み合わせによる歪み -
satisfies
で型を表現 -
satisfies
は難しそう?いや文字数が長いだけ
-
-
20日目 ECMAScript Private Fields
- TypeScriptにおけるprivateとECMAScript Private Fields
- コンパイラ・ランタイムの対応状況と運用
- 実際の業務ではどう使う?
- まとめ
- おまけ サンプルコード全容
-
21日目 using宣言
- ECMAScriptの進化と
using
宣言-
using
宣言とは? -
finally
とtry
だけの組み合わせをシンプル化 - デバッグ用ツールへの導入例
-
using
はリソース破棄だけに使うべきか - 将来への期待
-
- おまけ:計測処理の全容
- ECMAScriptの進化と
第4部 モダンWebアプリケーション開発現場からの実例集
-
15日目 App Router 時代のエラーハンドリング
- 2年前からのエラーハンドリングの変化
- App Routerでのエラーハンドリングの難しさ
-
e instanceof
に頼らないハンドリングへの回帰 - RSCからClient componentへのインスタンス渡しの問題
- 早期発見の仕組みのために点検を
- エラーハンドリングは最優先で習得すべきスキル
-
16日目 実例
Result<T, E>
- エラーの系統を考察する
- プラットフォームがエラーメッセージを加工する盲点
-
throw
からResult<T, E>
への転換 -
Result<T, E>
型 - さらなる欲求
- 戦略的な割り切り
- 学びと総括
-
17日目 実例
ConvenienceFixture
,orDefault()
- テストとモックの煩雑さに立ち向かう
- Branded typesとテストモックの両立
-
ConvenienceFixture
型とorDefault()
関数 -
ConvenienceFixture
型の型テスト
-
18日目 実例
PageContext
,AllowTransitionFrom
- App Routerへの大規模リアーキテクチャ
- 複雑なパラメータを管理する
PageContext
という概念を整備- どこで使いたいものか、どこでなら再利用してよいのか
- 複雑な遷移を型レベルで制御
-
AllowTransitionFrom
型の実例 - なぜページ名の分岐パラメータを増やさないのか
- 「自由を奪う」ことのメリット
-
- まとめ
-
19日目 実例
UnknownifyDiscriminatedUnion
-
PageContext
とsubject
パラメータ -
extractPageContext()
関数でPageContext
を作成 -
InferInput<T>
とunknown
-
subject
以外をすべてunknown
に - 型テストの実例
-
any
回避とunknown
の採用
-
第5部 昨今の開発環境とエコシステムを追いかける
-
22日目 tsx TypeScript Execute
- tsx とは
- Node.jsでTypeScriptを動かす
- CJS, ESMの移行過渡期による混迷と、tsxの登場
- TypeScriptランタイムとしての選択肢
- WinterCGの動き
- それでもtsxがしっくりくる
- tsx とは
-
23日目 tsupでバンドルする
- JavaScriptのモジュール史とバンドル文化
- ESMが正式に実装される流れ
- 2024年現在の様子
- tsupが生まれた背景
- なぜtsupが優れているか
- 省コンフィグ
- tsupの裏側
- まとめ
- JavaScriptのモジュール史とバンドル文化
-
24日目 Biomeを使ったLintとフォーマット
- ESLintというlintツール
- Prettierというフォーマットツール
- Biomeの台頭
- Biomeへの乗り換え手順
- タブインデントへの抵抗感
- 5匹の猿の実験
- 今後のBiomeに期待
-
25日目 今後のTypeScriptに期待すること
- TypeScriptへの期待
- TypeScriptはここ数年でも進化を続けている
- 今後を自由に妄想
-
NonNullable<T>
のsugar記法がほしい -
ConstraintOf<T>
のような型制約を取り出すユーティリティ型 - 高カインド型 (HKT) も欲しい
- 型のパターンマッチも欲しい
-
- TC39提案の動向
- WASMの進化はどうなるか
- WASMとJSを両方出力する言語が流行る?
- 遥か未来のWebアプリケーション開発
- Webブラウザ界に一波乱あるか
- AIフレンドリーなコード
- TypeScript 一人 Advent Calendar 2024のしめくくり
- TypeScriptへの期待
索引
記号・数字
-
__brand
(Branded Types Idiom) /2218
,2219
,2402
-
--strictNullChecks
/ → Strict Null Checks -
-readonly
/ → Mapping Modifiers -
!
/ → Non-null Assertion Operator -
?:
/ → Mapped Types -
?.
(オプショナルチェーン演算子) /2411
-
? :
/ → Conditional Types -
.cjs
(拡張子) /2423
-
.cts
(拡張子) /2423
-
.editorconfig
/2424
-
.js
(拡張子) /2423
-
.mjs
(拡張子) /2423
-
.mts
(拡張子) /2423
-
.test-d.ts
(拡張子) /2414
-
.ts
(拡張子) /2422
-
.tsx
(拡張子) /2422
-
""
(空文字列) /2212
,2219
-
"use client"
(React) /2415
-
[...arr]
/ → Spread Syntax -
[]
(空配列) /2212
-
[0]
/ → Indexed Access Types -
[number]
/2205
-
[object Object]
/2218
-
[P in K]
(Mapped Types) /2209
-
[P in keyof T]
(Mapped Types) /2209
-
@testing-library/react
/2204
-
#
(Private Fields) /2420
-
+?:
/ → Mapping Modifiers -
<T>
/ → ジェネリクス -
| null
(Nullable) /2206
,2217
-
|
/ → Union Types -
$()
(筆者作、Valibot) /2405
-
${T[P]}
(Template Literal Types) /2209
- 5匹の猿の実験 /
2424
A
- Abstract Operations (ECMAScript) /
2212
- Action (Valibot) /
2404
- AI /
2425
- Ajv /
2211
,2225
-
AllowTransitionFrom
型 (筆者作) /2418
- AltJS /
2423
- Anders Hejlsberg (人名) / → アンダース・ヘルスバーグ(人名)
- Andreas Kling (人名) /
2425
-
any
/2203
,2204
,2206
,2210
,2211
,2215
,2219
,2223
,2225
,2407
,2408
,2419
- App Router (Next.js) /
2415
,2416
,2418
,2419
- Apple Intelligence /
2425
-
Array.prototype.filter()
/2217
,2425
-
Array.prototype.find()
/2413
-
Array.prototype.includes()
/2220
-
Array.prototype.map()
/2209
,2222
-
Array.prototype.reverse()
/2210
-
Array.prototype.sort()
/2210
-
Array.prototype.toReversed()
/2210
-
Array.prototype.toSorted()
/2210
-
Array<T>
/2203
,2222
-
as const
/2220
,2411
,2412
-
as unknown as
/2206
,2219
-
as
(Key Remapping viaas
) /2219
-
as
(Type Assertions) /2218
,2219
,2220
,2412
-
asFilledString()
(筆者作) /2219
- AssemblyScript /
2425
-
assertExists()
(筆者作) /2217
,2411
,2413
- Assertion Functions /
2217
,2219
,2222
,2225
- Assertion Signature /
2217
-
assertMatchedTypes()
(筆者作) /2225
,2401
-
asserts v is T
/ → Assertion Signature -
assertString()
(筆者作) /2219
-
asString()
(筆者作) /2219
-
Awaited<T>
/2202
,2203
,2213
- axios /
2214
B
- Babel /
2423
,2424
-
ban-types
(typescript-eslint) /2215
-
beforeEach()
/2204
,2410
- bikeshed /
2207
- Biome /
2424
- Blink /
2425
-
Boolean
(コンストラクタ) /2215
- Bower /
2423
-
brand()
(Valibot) /2402
,2403
,2404
-
Brand<K, T>
/2218
,2219
- Branded Types /
2218
,2219
,2402
,2403
,2406
,2417
,2418
- Browserify /
2423
- Bun /
2422
-
button
(HTML Element) /2205
C
- Call this operator (TC39) /
2425
-
Capitalize<S>
/2216
-
catch
/2223
,2415
,2421
- Change Array by copy (TC39) /
2210
- ChatGPT /
2425
- Chris Wanstrath (人名) /
2425
- Chromium /
2422
- CI /
2415
- CJS /
2422
,2423
-
class
/2205
,2210
,2218
,2218
,2223
,2415
,2421
- Claude /
2425
- Clean Architecture 達人に学ぶソフトウェアの構造と設計 (書籍) /
2418
- CMS /
2208
- COBOL /
2425
- CommonJS / → CJS
-
ComputeRange<N, Result>
(引用) /2224
- Conditional Types /
2203
,2208
,2213
,2216
,2222
,2225
-
const
Assertion /2220
-
constructor
/2205
,2210
,2218
-
ConstructorParameters<T>
/2205
-
ConvenienceFixture
型 (筆者作) /2417
-
convertOrElse()
(筆者作) /2222
- Create missing branches (WebStorm) /
2221
- CSS in JS /
2224
- Custom Hook /
2204
- C 言語 /
2221
D
- Dan Abramov (人名) /
2223
-
Date.now()
/2403
-
DeepReadonly<T>
(ts-essentials) /2406
-
delete
演算子 /2211
- Deno /
2223
,2422
- Design by Contract /
2225
- Destructuring assignment /
2413
-
DetailedHTMLProps
/2205
- Discriminated union /
2208
,2409
,2413
,2416
,2418
,2419
-
Double<T>
(筆者作) /2209
- DRY (Don't repeat yourself) /
2205
,2409
E
- ECMAScript /
2209
,2219
,2220
,2221
,2222
-
ECMAScript Private Fields
/2420
- ECMAScript 仕様書 /
2215
,2223
,2404
- Either モナド /
2223
,2416
- Electron /
2202
,2423
- Emotion (CSS in JS) /
2224
-
enum
/2220
-
Equals<X, Y>
(引用) /2225
-
Err<E>
/2223
,2416
-
Error
/2223
,2415
- ES Module / → ESM
- ESLint /
2204
,2215
,2424
-
eslint-disable-next-line
/2204
- ESM /
2422
,2423
-
Exclude<T, U>
/2208
-
exists()
(筆者作) /2217
,2410
-
expectTypeOf()
(Vitest) /2414
- Explicit Resource Management (TC39) /
2421
-
explicit-function-return-type
(typescript-eslint) /2204
-
export
/2208
- Express.js /
2420
-
extends
(Generic Constraints) /2203
,2409
-
extends
(Inferring) /2203
-
extends
(Subclass) /2203
,2223
-
Extract<T, U>
/2208
,2212
,2408
,2409
-
ExtractKeyOf<T, K>
(筆者作) /2408
-
extractPageContext()
(筆者作) /2419
F
-
FilledString
(筆者作) /2219
,2403
,2419
-
finally
/2421
- Firestore /
2201
,2202
,2225
- Flat Config (ESLint) /
2424
- fp-ts /
2223
,2416
- Function overloads /
2413
G
- Gecko /
2425
- Gemini /
2425
- Generic Constraints /
2203
- Generics /
2209
,2222
-
getServerSideProps()
(Next.js) /2418
- GitHub Copilot /
2221
,2425
-
globalThis.parseInt()
/2205
- GoF (Gang of four) /
2418
- Google /
2425
- Go 言語 /
2423
- GraphQL /
2213
,2222
,2225
H
- Haskell /
2213
,2223
,2416
-
HasProperty
(ECMAScript) /2212
- Higher Kinded Types / → 高カインド型
-
hooksTestingToolsFactory()
(筆者作) /2410
- IDE /
2221
I
-
if
文 /2204
,2220
,2221
- immutable /
2210
-
import
/2423
- Indexed Access Types /
2205
,2220
-
infer
/2203
,2205
,2213
,2216
-
InferInput<T>
(Valibot) /2419
-
InferOutput<T>
(Valibot) /2401
,2402
,2406
-
inferred
(筆者作) /2204
-
Infinity
/2404
-
instanceof
演算子 /2217
,2223
,2415
-
interface
/2218
- Intrinsic String Manipulation Types /
2216
-
intrinsic
/2216
-
is()
(筆者作) /2409
-
Item
(筆者作) /2207
,2218
,2219
-
ItemId
(筆者作) /2218
,2417
-
Iterable<T>
/2203
J
- Java /
2213
,2218
,2420
- JavaScriptCore /
2422
- Jest /
2204
,2206
,2207
,2403
, → Vitest - JOIN (SQL) /
2202
- JSON /
2211
,2217
- JSON Schema /
2211
-
JSON.parse()
/2407
-
JSON.stringify()
/2218
K
L
- Labeled Tuple Elements /
2205
- Ladybird /
2425
- Language Service /
2221
-
let
(変数宣言) /2201
,2204
,2410
-
lib.dom.d.ts
/2214
-
lib.es5.d.ts
/2203
,2216
- Literal Types /
2220
,2224
-
looseObject()
(Valibot) /2405
-
Lowercase<S>
/2216
M
-
Map<K, V>
/2215
-
mapOrElse()
(筆者作) /2222
- Mapped Types /
2209
,2211
,2212
,2213
,2214
,2215
,2216
,2219
,2222
,2225
- Mapping Modifiers /
2211
,2212
,2213
,2214
-
match
(筆者作) /2416
- mattmccutchen (人名) /
2225
-
maxArrayLengthNotSpecified()
(筆者作) /2404
-
maxStringLengthNotSpecified()
(筆者作) /2404
- Maybe モナド /
2223
- Michal Zalecki (人名) /
2218
- Microsoft Copilot /
2425
-
Millisecond
型 (筆者作) /2403
- MoonBit /
2425
- MSW /
2420
-
MswServer
(筆者作) /2420
-
mui
/2205
-
mustFind()
(筆者作) /2413
,2414
N
- Narrowing /
2217
,2221
,2223
,2225
,2409
,2413
,2414
-
never
/2203
,2208
,2215
,2217
-
neverUsed()
(筆者作) /2405
- Next.js /
2206
,2218
,2411
,2415
,2416
,2418
,2419
-
NextApiRequest
/2206
-
NextApiResponse
/2206
- Node.js /
2422
,2423
-
node-sqlite
/2202
- Nominal Typing /
2218
,2418
- Nominal Typing Like な class /
2218
- Non-null Assertion Operator /
2218
-
NonNullable<T>
/2217
,2410
,2425
-
noUncheckedIndexedAccess
/2411
- npm /
2423
- Null- and undefined-aware types /
2217
-
null
/2212
,2213
,2217
,2219
-
null
チェック /2217
-
Number.MAX_SAFE_INTEGER
/2404
-
Number.POSITIVE_INFINITY
/2404
-
Number
(コンストラクタ) /2215
Discussion