1 今回の授業概要と連絡
本科目は学修単位科目です。大学の授業と同様に 1回の授業あたり4時間相当の授業時間外学習 を前提としたボリューム、展開速度となっています。いろいろと忙しいとは思いますが、時間を確保して取り組んでください。
1.1 小テスト❶
小テスト❶を実施します。
1.2 ここまでの流れ
後期中間試験ぐらいまでの授業の流れ (予定)
- モダンTypeScript基礎学習のための環境構築 済
- TypeScript基礎学習 ← 今回と次回の授業のメイン
- React / Next.js 開発に関連する文法や機能だけを集中的に学びます。
- Reactを使ったTodoアプリのための環境構築
- Todoアプリ開発(Reactによるフロントエンド開発)のチュートリアル
- Todoアプリのカスタマイズや作り込み → 後期前半の大課題
まずは、次のようなTodoアプリ (Reactを採用したフロントエンド開発) を目標とします。
- Todoアプリのサンプル (ギリギリ合格水準のレベル、点数で言えば60点😨)
- Todoアプリのサンプル (ここまでつくれたら素晴らしい!90点超🎉)
2 前回の復習
前回の授業内容の重要部分の復習と、プラスアルファの解説をしていきます。
2.1 静的型付け
前回講義において「TypeScriptは「静的型付け言語」であり、変数宣言時には次のようにコロン
(:) につづけて型 (string や
number)
を示す必要がある」と解説しました。
let name: string = "TypeScriptの勉強"; // : string で 文字列型を明示
let priority: number = 3; // : number で 数値型を明示ここで「変数に静的な型付けがされる」とは、(簡単に言えば) 変数宣言後、その変数には宣言時に示した型以外の値を (基本的には) 代入できない ということになります。
例えば、name: string = ... のように変数宣言された
name には 文字列型 (string型)
以外の値を入れること
はできず、また、priority: number = ...
のように変数宣言した priority には数値型 (number型)
以外の値を入れることはできません。
次のコードを記述し、実際にエラーとなることを確認してください。前回構築した環境でプログラムを実行するには、VSCodeで
[Ctrl]+[J] のショートカットでターミナルを起動し npm run dev を入力します。
export {}
let name: string = "TypeScriptの勉強";
let priority: number = 3;
// number型の値 (4649) を代入"High"
name = 4649;
// string型の値 ("High") を代入
priority = "High";VSCodeなどのエディタ上で (あるいは tsc
コマンドの実行ログで)、第07行目 については ‘number’ を型 ‘string’
に割り当てることはできません。(Type ‘number’ is not assignable to
type ‘string’.) のようなエラーが表示されます。
同様に 第10行目 において「型 ‘string’ を型 ‘number’ に割り当てることはできません。(Type ‘number’ is not assignable to type ‘string’.)」のようなエラーが表示されます。
なお、TypeScript / JavaScript
においては、慣例的に「変数名
(letで宣言)」や「ローカルな定数名
(constで宣言)」は キャメルケース (小文字はじまり)
を原則とするので覚えておいてください。
PythonやJavaScriptは動的型付け言語
プログラミング1で学んだ Python や JavaScript は「動的型付け言語」であり、次のような型を意識しないコードを記述をしても問題ありません。
なお、C言語は「静的型付け言語」なので、上記のようなプログラムはコンパイルエラーとなります。
命名規則
「キャメルケース」とは 小文字で開始して単語区切りに大文字
を使用する命名規則です。例えば newName や
isDone のように命名するものです。
「パスカルケース」とは
大文字で開始して単語区切りにも大文字
を使用する命名規則です。例えば NewName や IsDone
のように命名するものです。
TypeScriptの主要な「型」としては、次のようなものがあります。なお、null
と undefined については、あとの授業で扱います。
string: 文字列型。number: 数値型。整数型と浮動小数点型 の区別はありません。boolean: 真偽値型 (ブール型)。trueとfalseの2値だけを扱います。- Python では
TrueとFalseのように真偽値のリテラルは大文字開始 でしたが、TypeScript では 先頭が小文字 になることに注意してください。
- Python では
Date: 日時型。厳密には TyepScript / JavaScreipt の 組込みクラス であるDataのインスタンス (オブジェクト) の型で「日付」と「時刻」を扱うときに使用します。
2.1.1 定着確認
- TypeScriptにおいて「真偽値」を扱う型を答えよ。プログラム内の表記形式で答えること。
- 答え
boolean
- 答え
- TypeScriptにおいて「文字列」を扱う型を答えよ。プログラム内の表記形式で答えること。
- 答え
string
- 答え
- TypeScriptにおいて、浮動小数点数や整数を扱う型を答えよ。プログラム内の表記形式で答えること。
- 答え
number
- 答え
- TypeScript / JavaScript
において、「変数名」や「ローカルな定数名」の表記は慣例的に
???が使用される。???にあてはまる語として最も適切なのは「キャメルケース」「パスカルケース」「スネークケース (大文字)」「スネークケース (小文字)」「ハンガリアン記法」のうち、どれか。- 答え キャメルケース
2.2 型推論
ここまで「TypeScriptでは、変数や定数の宣言時に「型」を明示する必要がある」と説明してきました。しかし、実際には「型推論」という機能があり、(ユーザーが明示的に「型」を記述しなくても) 初期値から型を推論 (推測) して自動的に静的型付け を行なうことができます。
例えば、以下のTypeScriptプログラムは :string や
:number
を明示していませんが、問題なくトランスパイルされます
(VSCodeのエディタにもエラーは表示されません)。変数
name は "TypeScriptの勉強"
という初期値から 文字列型であると推論され、自動的に文字列型に型付け
されます。同様にpriority
は数値型に型付けされます。
各変数が「推論によって、どのように型付けされているか」は、VSCodeで以下のように 変数にカーソルを合わせること で確認できます。
また、次のように typeof
を使って推論された型を確認することもできます。実際に実行して、どのような結果が得られるか確認してください。typeof(name) ではなく
typeof name
のように使用する点に注意してください。
let name = "TypeScriptの勉強";
let priority = 3;
console.log(`name の型は ${typeof name} です`);
console.log(`priority の型は ${typeof priority} です`);なお、変数が 初期値を持たないとき や、関数を定義するとき などは明示的に型を記述する必要があります。学習の初期段階では、練習のために明示的に型を記述することをおすすめします。
2.2.1 定着確認
- TypeScriptにおいて、変数
hogeの型をコンソール出力したい。`console.log(`変数 hoge の型は ${???} です`);`の???に記述すべき適切な語を答えよ。- 答え
typeof hoge
- 答え
2.3 オブジェクトの初期化
TypeScript / JavaScript では、複数の変数をグループ化して (束ねて) オブジェクト という単位で扱うという解説をしました (参考:前回講義)。ここでの「オブジェクト」とは、既に学習済みの Pythonの「辞書 (またはクラスのインスタンス)」や C言語の「構造体」のようなもの と考えてください。
オブジェクトは、次のような「オブジェクトリテラル記法」で初期化することができました。
const todo = {
name: "TypeScriptの勉強",
priority: 3,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};この際、各プロパティ (属性) は キー: 値
という形式で定義され、カンマ ,
で区切って記述します。学習初期には
以下のような記述ミスが非常に多い
ので注意してください。
const todo = {
name = "TypeScriptの勉強"; // 正しくは name : "..."
priority = 3;
isDone = false; // 正しくは ; ではなく , で属性を区切る
deadline = new Date(2024, 9, 11, 9, 45);
};オブジェクトを JSON形式
に変換して整形してコンソール出力するためには console.log(JSON.stringify(todo, null, 2))
のようにすることも前回に学びました。
なお console.log(typeof todo) による出力は object となります。
3 前回講義の「演習」の解答例と解説
3.1 問題の確認
前回講義で、次のような演習問題に取り組んでもらいました。
次のような Date型 (日付・日時型) の変数 deadline
を追加して、コンソールメソッドで出力してください。また、dayjs
や moment などのライブラリを使わずに「2024/10/02
11:45」のようにコンソールに出力する方法について調べてください。
上記について、実際に取り組んでもらって、皆さんそれぞれが「自分なりの解決策」を見つけていることを前提に解説していきます。
3.2 解説: 月 (Month) の扱いについて
まず、これまでのプログラミングの経験から、Date(2024, 10, 2, 11, 45)
によって、おそらく「2024年10月2日
11時45分」という日時で初期化された値が、変数 deadline
に格納されるのだろう・・・と推測したと思います。
しかし、実際に console.log(deadline)
のように書いてコンソール出力すると、次のような結果になることが確認できたと思います。
2024-11-02T02:45:00.000Z
上記のような日時表記はISO8601形式とよばれる書式 (フォーマット) となります。私たちの日常生活では登場することは少ないですが、コンピュータやネットの世界ではオーソドックスな日時の表記法になっています。
さらに詳しく結果を考察・確認していきます。
まずは「Month (月)」について 「10月だろう」と推測していたものの出力結果が違った
ことに気づいたでしょうか。TypeScript / JavaScrfipt の
Date クラスの仕様上、第2引数は
ゼロオリジン で 0 から
11 によって Month (月)
を与えるようになっています
(ややこしいですが、そのような仕様なので仕方がありません)。
では、第2引数に 12 を与えるとどうなるのか (コンパイルエラーになるのか、実行時エラーになるのか、あるいは別の動作をするのか)
を予想したうえで実際に試してみてください。プログラミング1
の授業から、繰り返し伝えていますが、このように発想を広げて自ら検証してみることは非常に大事です。
これから開発しようとしている「Todoアプリ」において、タスクの期限 (deadline) が、1ヵ月ずれて扱われることは致命的なので注意してください。
3.3 解説: 時刻 (タイムゾーン) の扱いについて
次に時刻について「11:45」になると推測したと思いますが、実際の出力は
02:45:00.000
となりました。「9時間のずれ」が生じています。
つまり、Date の 第4引数 と
第5引数
を日本のローカル時刻で与えたものの、deadline には
協定世界時 (UTC: Universal time
coordinated) の日時 (時刻)
が記録される仕組みになっています。これも、ややこしいと感じるかもしれませんが、仕様なので仕方ありません。
JS / TS 実行環境のタイムゾーンを確認する方法
現在の JS / TS の実行環境 (Node.jsやウェブブラウザ) が認識しているタイムゾーンは、次のコードで確認することができます。
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(`Timezone: ${timeZone}`);おそらく、皆さんの実行環境では
Timezone: Asia/Tokyo
のようにコンソール出力されると思います。
ここでは JS/TSの実行環境によってタイムゾーンが変わること に注意してください。
特にウェブアプリのバックエンドを、クラウドサーバ や
Dockerなどのコンテナ で構築する場合、タイムゾーンは一般に
Timezone: UTC
となります。一方で、フロントエンドのタイムゾーンは利用者環境
(OS) によって違ってくることに注意してください。。
3.4 解説: 日時の整形出力
次に、Date型の変数の内容を「YYYY/MM/DD HH:MM」のような形式で整形出力する方法について考えていきます。ただし、まずは 外部ライブラリを使用しない前提 とします。
ウェブ検索を利用して「Date型の日時を整形出力する方法」について探す場合は「JavaScript Date フォーマット」などをキーワードにします。検索キーワードは 「TypeScript」ではなく「JavaScript」 としたほうが情報のヒット率が高くなります。
TypeScript固有の内容でなければ「JavaScript」をキーワードに使うことも方法として覚えておいてください。
GitHub Copilot を利用して解決を試みる場合は、以下のように 処理内容を的確に表現したコメント をプログラムに書くことでCopilotがコードを提案してくれます。
次に、ChatGPT や Claude
などの生成AIを利用して解決を試みる場合は、次のようなプロンプトを記述します。プロンプトのなかで、プログラムコード全体を
3連バッククォート ```
で囲む
ことで、より適切に読み込みされます。また、プロンプトのなかでもコードの断片は
バッククォートで囲むこと が推奨されます。
次に示す TypeScriptプログラムに続けて、変数 `deadline` の内容を「2024/11/02 11:45」のようにコンソールに整形出力するプログラムを書いてください。実行環境は Node.js、タイムゾーンは `Timezone: Asia/Tokyo` を想定し、外部ライブラリを使用しない前提で記述してください
```
export {};
let deadline: Date = new Date(2024, 10, 2, 11, 45);
console.log(deadline);
```
ここでは、生成AIから次のような回答が得られた仮定とします。
export {};
let deadline: Date = new Date(2024, 10, 2, 11, 45);
// 年、月、日、時、分を取得してフォーマット
const year = deadline.getFullYear();
const month = String(deadline.getMonth() + 1).padStart(2, '0'); // 月は0から始まるため +1
const day = String(deadline.getDate()).padStart(2, '0');
const hours = String(deadline.getHours()).padStart(2, '0');
const minutes = String(deadline.getMinutes()).padStart(2, '0');
// フォーマットした文字列をコンソールに出力
console.log(`${year}/${month}/${day} ${hours}:${minutes}`);第12行目では、前回学習したテンプレート文字列が使用されています。提案されたプログラムを実行すると、次のように意図した結果を得ることができます。
2024/11/02 11:45
生成AIを利用してプログラムを得たときには、動作確認後に 必ずプログラムの意味を理解 するように努めてください。「プログラムの意味は分からないけど、なんか動いているのでOK」では、エンジニアを目指す人間としてダメダメ🤪です (プロの通訳や翻訳家を目指している学生が、生成AIに翻訳させて、そのまま提出するのと同じくらいヤバいです。あるいは「電卓を使えば計算できるから \(0.8\times 2 - 9.2\) を自力で計算できなくてもOK」という感覚ぐらいヤバいです)。
例えば、第08行目
では「deadline.getHours() メソッドで 値
(number型・ローカルタイムゾーンに基づいた「時」)
を得て、それを String() で文字列
(string型) に変換して、さらに文字列の
padStart(2, '0') メソッドで ゼロ埋めの2文字幅
に変換している」ということを理解し、説明できる必要があります。そのためには、生成AIに「自分の解釈の確認をしてもらったり、不明点を追質問したり、コードを書いて実験したりすること」が必要です。
(例)
次に示すTypeScriptの第2行目では、deadline.getHours() メソッドで 値 (number型、ローカルタイムゾーンに基づいて変換された値) を得て、それを String() で文字列 (string型) に変換して、さらに文字列の padStart(2, ‘0’) メソッドを利用してゼロ埋めの2文字幅に変換している、という解釈は正しいですか。
let deadline: Date = new Date(2024, 10, 2, 11, 45); const hours = String(deadline.getHours()).padStart(2, '0');
Pythonで日時を扱って整形出力するには?
Pythonで、先の prac01.ts
と同様のプログラムを書くと次のようになります。
from datetime import datetime # 日時を扱うための datatime ライブラリ
deadline = datetime(2024, 10, 2, 11, 45)
print(deadline.strftime('%Y/%m/%d %H:%M'))実際に実行してみてください (paiza.io) 。実行結果の違いに気づいた でしょうか?
- Python の
datetimeクラスでは、月 (Month) は1から12の整数で与えて初期化します。1月は1、2月は2、…、12月は12となります。 - JavaScript (TypeScript) の
Dateクラスでは、月 (Month) は0から11の整数で与えて初期化します。1月は0、2月は1、…、12月は11となります。
3.5 解説: 日時の整形出力 (関数化1)
ここまでの内容で、次のようなコードでDate型のオブジェクトを「2024/11/02
11:45」のような形式で出力できることが分かりました。deadline
の変数宣言キーワードを let から const
に変更しています。
export {};
const deadline: Date = new Date(2024, 10, 2, 11, 45);
const year = deadline.getFullYear();
const month = String(deadline.getMonth() + 1).padStart(2, '0');
const day = String(deadline.getDate()).padStart(2, '0');
const hours = String(deadline.getHours()).padStart(2, '0');
const minutes = String(deadline.getMinutes()).padStart(2, '0');
console.log(`${year}/${month}/${day} ${hours}:${minutes}`);しかし、上記のコードは 再利用性 の面で大きな課題があることに気付くと思います。
例えば、Todo の「作成日時」を
createdAt という変数に格納しておいて
期日 2024/11/02 11:45 (登録日: 2024/10/11 09:45)
…のように出力したいとします。
上記のコードに準じて愚直にコードを書くと以下のようになってしまいます。実際にコピペして実行してみてください。
export {};
const deadline: Date = new Date(2024, 10, 2, 11, 45);
const createdAt: Date = new Date(); // 引数なしで現在日時を取得
const dlYear = deadline.getFullYear();
const dlMonth = String(deadline.getMonth() + 1).padStart(2, "0");
const dlDay = String(deadline.getDate()).padStart(2, "0");
const dlHours = String(deadline.getHours()).padStart(2, "0");
const dlMinutes = String(deadline.getMinutes()).padStart(2, "0");
const caYear = createdAt.getFullYear();
const caMonth = String(createdAt.getMonth() + 1).padStart(2, "0");
const caDay = String(createdAt.getDate()).padStart(2, "0");
const caHours = String(createdAt.getHours()).padStart(2, "0");
const caMinutes = String(createdAt.getMinutes()).padStart(2, "0");
const str =
`期限 ${dlYear}/${dlMonth}/${dlDay} ${dlHours}:${dlMinutes} ` +
`(登録日 ${caYear}/${caMonth}/${caDay} ${caHours}:${caMinutes})`;
console.log(str);確かに意図する出力は得られますが 保守性 や 再利用性 の面では、あまりにも酷いコード🫠です。既に Python と C言語 を学んできている皆さんであれば、処理の関数化 で解決できることに気付くと思います。
3.6 解説: 日時の整形出力 (関数化2)
Date型のオブジェクトを「引数」として受け取って「YYYY/MM/DD
HH:MM」形式の文字列を「戻り値 (返り値)」とする
date2str という関数の作成を例に
TypeScriptにおける関数定義の書き方
を学んでいきます。
まず、結論から言えば、以下の
第04行目から第11行目
のように関数 date2str が定義できます。
export {};
// 関数の定義
function date2str(dt: Date): string {
const year = dt.getFullYear();
const month = String(dt.getMonth() + 1).padStart(2, "0");
const day = String(dt.getDate()).padStart(2, "0");
const hours = String(dt.getHours()).padStart(2, "0");
const minutes = String(dt.getMinutes()).padStart(2, "0");
return `${year}/${month}/${day} ${hours}:${minutes}`;
}
const deadline: Date = new Date(2024, 10, 2, 11, 45);
const createdAt: Date = new Date(); // 引数なしで現在日時を取得
// 関数の呼出し (テンプレート文字列の内部)
let str = `期限 ${date2str(deadline)} (登録日 ${date2str(createdAt)})`;
console.log(str);特に第04行目の関数定義の部分
function date2str(dt: Date): string {
に注目してください。
TypeScriptでは、関数の定義に function
キーワードを使用します (Pythonでは def
を使用しました)。そして、丸括弧で囲んで関数内で使用する引数を型付きで与えて、さらに、戻り値の型を記述します。
特に、慣れるまでは「戻り値の型を記述する位置が分かりづらい」ので注意してください。
他にも、関数記述の例を見てみましょう。
2個の数値型の引数を受け取って、真偽値型を戻り値とする
comp という関数のシグネチャ (=関数の基本的な情報を定義する部分)
は次のようになります。
1個の文字列型の引数を受け取って、戻り値を持たない
printWord
という関数のシグネチャは次のようになります。TypeScript
では、慣例的に関数名についても キャメルケース が使われます。
戻り値が「ない」ことは void
引数を受け取らず、数値型を戻り値とする
dice という関数のシグネチャは次のようになります。
なお、引数がないことを
function dice(void): number { ... } のように
void を使って明示することは できません。
3.6.1 定着確認
- 引数を受け取らず、数値型を戻り値とする
diceという関数のシグネチャを答えよ。 - 1個の数値型の引数 (仮引数を
numとする) を受け取り、文字列型を戻り値とするnum2strという関数のシグネチャを答えよ。 - 2個の文字列型の引数 (仮引数を
word1とword2とする) を受け取り、真偽値型を戻り値とするcompという関数のシグネチャを答えよ。 - 1個のDate型の引数 (仮引数を
birthdayとする) を受け取り、数値型を戻り値とするgetAgeという関数のシグネチャを答えよ。
3.7 アロー関数
モダンTypeScriptでは function
キーワードを使った関数定義よりも、=> を使用した
アロー関数
という関数定義が一般に使用されます (トレンドになっています)。ウェブの情報も「アロー関数」で書かれていることが多い
ので、基本的には =>
によるアロー関数を使用するようにしてください。
先ほどの date2str
は、次のようにアロー関数形式に書き換えができます。
実際にアロー関数形式に書き換えて、同じようにプログラムが動作することを確認してください。
3.7.1 定着確認
- 引数を受け取らず、数値型を戻り値とする
diceという関数のシグネチャを「アロー関数形式」で答えよ。 - 1個の数値型の引数 (仮引数を
numとする) を受け取り、文字列型を戻り値とするnum2strという関数のシグネチャを「アロー関数形式」で答えよ。 - 2個の文字列型の引数 (仮引数を
word1とword2とする) を受け取り、真偽値型を戻り値とするcompという関数のシグネチャを「アロー関数形式」で答えよ。 - 1個のDate型の引数 (仮引数を
birthdayとする) を受け取り、数値型を戻り値とするgetAgeという関数のシグネチャを「アロー関数形式」で答えよ。
3.8 関数を別ファイルに分離する
関数 date2str
は、他のプログラムからも使用する可能性があるので別ファイルに分けて記述します。プロジェクトフォルダに
utils (utilitiesの略) を作成して、そのなかに
date2str.ts というファイルを作成して、
以下のように関数 date2str
を抜き出して貼りつけて保存してください。
export const date2str = (dt: Date): string => {
const year = dt.getFullYear();
const month = String(dt.getMonth() + 1).padStart(2, "0");
const day = String(dt.getDate()).padStart(2, "0");
const hours = String(dt.getHours()).padStart(2, "0");
const minutes = String(dt.getMinutes()).padStart(2, "0");
return `${year}/${month}/${day} ${hours}:${minutes}`;
};
ここで、第01行目 の先頭に export というキーワード
をつけていることに着目してください。この export
をつけた関数は
別ファイルに書かれたプログラムから呼び出すことが可能
となります。また関数以外にも、数値や文字列などを格納した変数や定数についても同様に作用します。
実際に utils/date2str.ts に定義した関数
date2str が、別ファイルの prac01.ts
から呼び出せることを確認します。prac01.ts
を以下のように書き換え、動作することを確かめてください。
export {};
import { date2str } from "./utils/date2str"; // 関数date2strをインポート
const deadline: Date = new Date(2024, 10, 2, 11, 45);
const createdAt: Date = new Date(); // 引数なしで現在日時を取得
let str = `期限 ${date2str(deadline)} (登録日 ${date2str(createdAt)})`;
console.log(str);上記の 第02行目 で、関数 date2str
がインポートされ 第07行目
で呼び出されています。
ここで注意してほしいことは、index.ts
に記述したような import "./utils/date2str"
の形式ではなく
import { date2str } from "./utils/date2str";
の形式でインポートしていることです。通常、TypeScript
では、後者の形式を使って export
キーワードをつけた関数や変数「だけ」がインポートされるようにします。
また、from "./utils/date2str.ts"; ではなく
from "./utils/date2str";
のように「拡張子」が省略されている
ことにも注意してください。
なお utils/date2str.ts で export
キーワードを削除すると、プログラムが動作しなくなることも確認してください。
4 ライブラリのインストールと利用
関数を自作してDate型を整形出力する方法について解説しました。ここからは 外部のライブラリ (パッケージ) を利用して同様のことを行なってみます。ここではdayjsというライブラリを使用します。
4.1 dayjsライブラリのインストール
プロジェクフォルダに dayjs をローカルインストールするために、以下のコマンドを実行してください。
npm i dayjs
前回、開発環境を構築するときには
npm i -D typescript ts-node nodemon @types/node
のように -D オプションを付けました。この
-D は 開発だけに使用するライブラリ
(=トランスパイルされたあとのプログラムの実行には不要なライブラリ)
をインストールするときにつけます。ここで使用する
dayjs は、実行時に使用するライブラリなので
-D を 付けず に npm
を実行します。
インストールされたことを以下のコマンドで確認してください。
npm list --depth=0
次のような応答が返ってくると思います。一覧に
dayjs@1.11.13
が含まれていることを確認してください。@
以降はバージョン番号なので、適宜、読み替えてください。
npm list --depth=0
learn-ts-basics@ C:\Users\xxxx\Documents\learn-ts-basics
├── @types/node@22.7.4
├── dayjs@1.11.13
├── nodemon@3.1.7
├── ts-node@10.9.2
└── typescript@5.6.2
-D
オプションをつけてインストールしたか、そうでないかは
package.json
の内容から確認することができます。VSCodeで
package.json を確認すると -D
を付けてインストールしたライブラリ (パッケージ)
は "devDependencies"
に記述されます。また、-D
を付けずにインストールしたライブラリは
"dependencies" に記述されます。
現段階ではまだ利用しませんが バンドル という処理をする際に、これらの情報が意味を持つようになります。
{
"devDependencies": {
"@types/node": "^22.7.4",
"nodemon": "^3.1.7",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
},
"scripts": {
"start": "node dist/index.js",
"build": "tsc",
"dev": "nodemon --watch src --ext ts --verbose --exec ts-node src/index.ts"
},
"dependencies": {
"dayjs": "^1.11.13"
}
}バンドル (bundle) とは、複数のJavaScriptファイルやその 依存関係 を「1つのファイルにまとめる処理」のことで、ウェブアプリケーションの配信と実行を効率化するために使用されます。主なバンドルツールにはwebpack、Vite、Turbopack、Parcel などがあります。
依存 (dependency) とは、そのアプリを正常に動作させるために (あるいは開発するために) 必要な外部のパッケージ (ライブラリ) のことを意味します。
例えば package.json の
devDependencies
に記載されているのは、そのアプリを開発
(コンパイルやビルドなど) するために必要なパッケージ
になります。また、dependencies
に記載されているのは、そのアプリを開発するため
(コンパイルやビルドなどをするため)
に必要なパッケージになります。
4.1.1 定着確認
- アプリのの実行時に使用する
uuidというライブラリを、プロジェクトフォルダにローカルインストールしたい。これを実行するコマンドを答えよ。- 答え
npm i uuidまたはnpm install uuid
- 答え
- アプリの開発時だけに使用する
@types/uuidというライブラリを、プロジェクトフォルダにローカルインストールしたい。これを実行するコマンドを答えよ。- 答え
npm i -D uuidまたはnpm install --save-dev @types/uuid
- 答え
4.2 dayjsライブラリの利用
npm コマンドでインストールしたライブラリは
import xxxx from "yyyy"; や
import { xxx1, xxx2 } from "zzzz";
のようにインポートして使用します。
dayjs は、次のようにインポートして使用します。
export {};
import dayjs from "dayjs"; // dayjsのインポート
const deadline: Date = new Date(2024, 10, 2, 11, 45);
const createdAt: Date = new Date(); // 引数なしで現在日時を取得
const str =
`期限 ${dayjs(deadline).format("YYYY/MM/DD HH:mm")}` +
`(登録日 ${dayjs(createdAt).format("YYYY/MM/DD HH:mm")})`;
console.log(str);上記のプログラムでは 第02行目
でインポートされた dayjs を 第08行目
と 第09行目
で呼び出して使用しています。実際に実行して結果を確認してください。また、ここでは
"YYYY/MM/DD HH:mm"
という文字列が2回登場しているので、これを dtFmt
という定数にまとめると次のようなプログラムになります。
export {};
import dayjs from "dayjs";
const dtFmt = "YYYY/MM/DD HH:mm";
const deadline: Date = new Date(2024, 10, 2, 11, 45);
const createdAt: Date = new Date(); // 引数なしで現在日時を取得
const str =
`期限 ${dayjs(deadline).format(dtFmt)}` +
`(登録日 ${dayjs(createdAt).format(dtFmt)})`;
console.log(str);4.2.1 演習 (15分)
次のように「曜日」を含めた出力を得たい。そのような出力が得られるようにプログラムをアップデートしてください (dayjsライブラリを使用することを前提とする)。
期限 2024/11/02(土) 11:45(登録日 2024/10/08(火) 14:58)
- 生成AIやウェブ検索を利用して取り組んでください。
5 オブジェクトの型定義
ここからは prac02.ts
というファイルにコードを記述していきます。prac02.ts
を作成し、index.ts
を以下のように書き換えてください。
今回講義の2.3
オブジェクトの初期化
では、次のようなオブジェクトリテラルを使用して todo
を初期化しました。
const todo = {
name: "TypeScriptの勉強",
priority: 3,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};上記では、実は 推論によって name や
priority などの プロパティ (属性)
の型付け が行われています。実際に VSCode で
todo
にカーソルを合わせると次のように「推論された型」が確認できます。
オブジェクトに対して明示的に「型」を与えるときは、次のように
type
キーワードを使って「型」を定義して使用します。第02行目
から 第07行目
にかけて定義して、第10行目 で
const todo1: Todo = {
のようにして、todo1 を Todo
型として型付けしています。
// Todo型を定義
type Todo = {
name: string; // セミコロンで区切り
priority: number;
isDone: boolean;
deadline: Date;
};
// Todo型のオブジェクトを作成
const todo1: Todo = {
name: "TypeScriptの勉強", // カンマで区切り
priority: 3,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
// Todo型のオブジェクトを作成
const todo2: Todo = {
name: "基礎物理3の宿題",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 10, 16, 0),
};なお、「型定義」では、各プロパティ (属性) が セミコロン で区切られている点に注意してください (一方で、オブジェクトリテラルでは各プロパティが カンマ で区切られています)。また、型名は慣例的に 大文字からはじめるパスカルケース とする点に注意してください。
上記のように 明示的な型付け
をすることで、プログラミングのなかで生じる様々なミスを早期発見できるという恩恵が得られます。例えば、型付けせずに以下のように
todo1 と todo2
を定義すると、それに続く処理のなかで実行時エラーや予期せぬ結果の出力に悩まされる可能性が「大」です。
const todo1: Todo = {
name: "TypeScriptの勉強",
priority: "3",
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
const todo2: Todo = {
name: "基礎物理3の宿題",
priority: 1,
isDone: false,
deadlien: new Date(2024, 9, 10, 16, 0),
};上記のコードの「何が問題か」に気付けるでしょうか。
一方、もし明示的に型付けをしていれば、以下のように VSCode
のエディタ画面上で問題箇所をエラーとして表示してくれるようになります
(また tsc
のタイミングでもコンパイルエラーとして出力してくれます)。
C言語バージョン
上記のプログラムを、C言語で「構造体」を使用して記述すると以下のようになります。実際にコードを試したい場合はpaiza.ioを利用してください。
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
// Todo構造体を定義
typedef struct {
char name[100];
int priority;
bool isDone;
struct tm deadline;
} Todo;
int main() {
// Todo構造体のオブジェクトを作成
Todo todo1 = {
.name = "TypeScriptの勉強",
.priority = 3,
.isDone = false,
.deadline = {
.tm_year = 2024 - 1900,
.tm_mon = 9,
.tm_mday = 11,
.tm_hour = 9,
.tm_min = 45
}
};
// Todo構造体のオブジェクトを作成
Todo todo2 = {
.name = "基礎物理3の宿題",
.priority = 1,
.isDone = false,
.deadline = {
.tm_year = 2024 - 1900,
.tm_mon = 9,
.tm_mday = 10,
.tm_hour = 16,
.tm_min = 0
}
};
printf("Todo 1: %s, Priority: %d, Done: %s\n",
todo1.name, todo1.priority, todo1.isDone ? "true" : "false");
printf("Todo 2: %s, Priority: %d, Done: %s\n",
todo2.name, todo2.priority, todo2.isDone ? "true" : "false");
return 0;
}Pythonバージョン
上記のプログラムを、Pythonで「辞書型(dict)」を使用して記述すると以下のようになります。
from datetime import datetime
todo1 = {
"name": "TypeScriptの勉強",
"priority": 3,
"isDone": False,
"deadline": datetime(2024, 10, 11, 9, 45)
}
todo2 = {
"name": "基礎物理3の宿題",
"priority": 1,
"isDone": False,
"deadline": datetime(2024, 10, 10, 16, 0)
}
print(f"Todo 1: {todo1['name']}, Priority: {todo1['priority']}, Done: {todo1['isDone']}")
print(f"Todo 2: {todo2['name']}, Priority: {todo2['priority']}, Done: {todo2['isDone']}")また、Class
を使用して記述すると以下のようになります。
from datetime import datetime
class Todo:
def __init__(self, name: str, priority: int, is_done: bool, deadline: datetime):
self.name = name
self.priority = priority
self.is_done = is_done
self.deadline = deadline
def __str__(self):
log = f"Todo: {self.name}, Priority: {self.priority}, " + \
f"Done: {self.is_done}, Deadline: {self.deadline}"
return log
# Todoクラスのインスタンスを作成
todo1 = Todo(
name="TypeScriptの勉強",
priority=3,
is_done=False,
deadline=datetime(2024, 10, 11, 9, 45)
)
todo2 = Todo(
name="基礎物理3の宿題",
priority=1,
is_done=False,
deadline=datetime(2024, 10, 10, 16, 0)
)
print(todo1)
print(todo2)5.1 型定義を別ファイルに分離する
先ほどは関数を別のファイルに分離しましたが、同様に (複数のファイルから参照される可能性がある) 型定義も 別ファイルに分離 することができます。
実際に types.ts
というファイルを作成して「Todo型の定義」をそこに移動してください。そして、
prac02.ts のなかで
import { Todo } from "./types";
のようにインポートしてください。
なお、types.ts では Todo に export
キーワード を付けることを忘れないようにしてください。
(参考)
export {};
import { Todo } from "./types"; // 型定義の読込み
const todo1: Todo = {
name: "TypeScriptの勉強",
priority: 3,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
const todo2: Todo = {
name: "基礎物理3の宿題",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 10, 16, 0),
};
console.log(JSON.stringify(todo1, null, 2));
console.log(JSON.stringify(todo2, null, 2));5.2 オブジェクトを引数に受け取る関数の定義
Todoの型定義を参照して「Todo
オブジェクトを引数として受け取って、その内容をコンソール出力する
printTodo
という関数」を作成してみます。
まず、utils フォルダに printTodo.ts
というファイルを作成してください。次に、そのファイルに以下のプログラムを貼付けてください。
import dayjs from "dayjs";
import { Todo } from "../types";
export const printTodo = (todo: Todo): void => {
const todoSummary =
`(優先度: ${todo.priority}) ${todo.name}` +
` 期日: ${dayjs(todo.deadline).format("YYYY/MM/DD HH:mm")}`;
console.log(todoSummary);
};第02行目でTodo型の定義をインポートしています。相対パスによる指定 になるので
(types.ts は1つ上の階層に存在するので)
from ../types となります。
第04行目では、アロー関数として
printTodo
を定義してしています。(todo: Todo) のように
Todo型の値を、仮引数 todo
として受け取るように記述しています (仮引数と引数の違いとは)。
また、prac02.ts で、関数 printTodo
を使用するためには次のようにします。第03行目 で
printTodo
をインポートしています。相対パスで指定することに注意してください。
export {};
import { Todo } from "./types";
import { printTodo } from "./utils/printTodo";
// todo1 と todo2 の初期化処理 (略)
printTodo(todo1);
printTodo(todo2);実際に実行すると、次のような出力が得られます。
■ prac02.ts の実行
(優先度: 3) TypeScriptの勉強 期日: 2024/10/11 09:45
(優先度: 1) 基礎物理3の宿題 期日: 2024/10/10 16:00
5.3 分割代入
モダンTypeScriptでは 分割代入 という文法が多用されます。分割代入はReact開発でも頻繁に使うことになる文法なので、十分に理解して使えるようになってください。
分割代入 (destructuring assignment) とは オブジェクトから一部の値 (プロパティ) を抽出して、それを個別の変数に簡単に代入 する機能になります。以下のプログラムの 第05行目 が「分割代入」の実例になります。
import dayjs from "dayjs";
import { Todo } from "../types";
export const printTodo = (todo: Todo): void => {
const { name, priority, deadline } = todo; // 分割代入
const todoSummary =
`(優先度: ${priority}) ${name}` +
` 期日: ${dayjs(deadline).format("YYYY/MM/DD HH:mm")}`;
console.log(todoSummary);
};Todo型は
name、priority、isDone、deadline
の4つのプロパティを持ちますが、このうちの任意の3つを抽出して 同名の変数 に代入しています。
さきほどは 第07行目 を
`(優先度: ${todo.priority}) ${todo.name}` +
と書いていましたが、ここでは
`(優先度: ${priority}) ${name}` +
のように短く記述できています。
なお、分割代入は
const { deadline, priority, name } = todo のように
順番を変えても問題なく動作します。実際に確認してみてください。
この分割代入は、次のようなプログラムと実質的に同じとなります。
export const printTodo = (todo: Todo): void => {
const name = todo.name; // 通常の代入
const priority = todo.priority; // 通常の代入
const deadline = todo.deadline; // 通常の代入
const todoSummary =
`(優先度: ${priority}) ${name}` +
` 期日: ${dayjs(deadline).format("YYYY/MM/DD HH:mm")}`;
console.log(todoSummary);
};5.4 引数の分割代入
さらに、次の 第04行目 ように 引数の受け取りに分割代入を適用すること ができます。このテクニックもReact開発のなかで頻繁に利用されるので「何が行なわれているのか 」を正しく読み取れるようになってください。ウェブの解説や、生成AIが出力するサンプルコードでも、引数の分割代入が使用されていることが多いです。
import dayjs from "dayjs";
import { Todo } from "../types";
export const printTodo = ({name, priority, deadline}: Todo): void => {
const todoSummary =
`(優先度: ${priority}) ${name}` +
` 期日: ${dayjs(deadline).format("YYYY/MM/DD HH:mm")}`;
console.log(todoSummary);
};5.4.1 定着確認
- 次に示す
greet.tsのgreet関数を「アロー関数形式」に書き換えよ。 - アロー関数形式に書き換えた
greetの関数内処理を「分割代入」を利用したものに書き換えよ。 - アロー関数形式に書き換えた
greetを「引数の分割代入」を使ったものに書き換えよ。
type User = {
name: string;
age: number;
};
function greet(user: User): void {
console.log(`こんにちは、${user.name}さん。${user.age}歳ですね。`);
};
const person = { name: "鈴木", age: 30 };
greet(person);5.4.2 演習 (宿題: 20分)
Todo型の引数 (1個) を受け取って「現在時刻が期限
(deadline) を過ぎている」かつ「未完了
(isDone が false)」のとき
true 、そうでないときは false
を返す関数を実装してください
(アロー関数形式で別ファイルに記述してください)。また、その関数が適切に動作をすることを確認する簡単なテストコードを
prac03.ts
に記述してください。関数名と、それを記述するファイル名も、処理内容にあわせて適切に設定してください。
(ヒント) 変数や関数、ファイルの命名にも「生成AI」を活用することができます。
TypeScriptでXXXXアプリを開発しています。XXXXのような処理を行なう関数の名前を複数提案してください。
5.4.3 演習 (宿題: 20分)
Todo型の引数 (1個) を受け取って、完了済みであれば
【済】基礎物理3の宿題、未完了で期限を過ぎていなければ
【未】基礎物理3の宿題 (期限まで残りXX時間)、期限を過ぎていれば
【未】基礎物理3の宿題 (期限をXX時間超過)
のような文字列を返す関数
(アロー関数形式で、上記の演習と同じファイル内に記述)
を実装してください。また、その関数が適切に動作をすることを確認する簡単なテストコードを
prac03.ts に記述してください。
- 戻り値の文字列の内容はカスタイマイズやアレンジ歓迎です。
6 等価演算子と不等価演算子
6.1 値の比較
TypeScript (および JavaScript)
において「数値型」や「文字列型」などのプリミティブ型の値を比較するときは、一般に
=== (厳密等価演算子)
を使用することが推奨されます。
言語仕様としては == (等価演算)
も使用可能ですが、こちらは比較の際に 暗黙の型変換が適用
されることがあり、その挙動について十分な理解がないままに使用するとバグの原因となります。
console.log(3150 === "3150"); // false
console.log(0 === ""); // false
console.log("1,2,3" === [1, 2, 3]); // falseconsole.log(3150 == "3150"); // true
console.log(0 == ""); // true
console.log("1,2,3" == [1, 2, 3]); // trueなお、上記のサンプルコードは現在構築しているTypeScript環境では実行できません (厳密な型チェックをする設定になっているためトランスパイルの段階でエラーとして扱われます)。試したいときはTypeScript Playgroundを利用してください。
学習初期段階では == の使用を避け、===
を使用する習慣をつけることが望ましいです。基本的には == でなければ実現できない処理
は存在しません。===
と必要に応じての明示的な型変換を組み合わせることで、あらゆる比較操作が可能です。
同様に「等価ではないこと」を判定するためには !==
(厳密不等価演算子) を使用するようにしてください
(!= の使用は避けてください)。
6.2 オブジェクトの比較 (重要)
厳密等価演算子 (===) あるいは等価演算子
(==)
による「オブジェクトの比較」では、オブジェクトの「参照」の比較
が行われ、参照が同じであれば true、そうでなければ
false
を返します。配列についても同様に「参照の比較」が行なわれます。
オブジェクトの「参照」とは、C言語で言えば「ポインタ」、Pythonで言えば「オブジェクトID」に相当するものです。
例えば、以下の todo1 と todo2
は、同じ値のプロパティを持っていますが、それぞれ別のオブジェクト
(つまり、異なる「参照」、C言語的に言えば異なる「アドレス」、Pythont的に言えば異なる「オブジェクトID」)
であるため、第18行目 の出力は false となります。
export {};
import { Todo } from "./types";
const todo1: Todo = {
name: "TypeScriptの勉強",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
const todo2: Todo = {
name: "TypeScriptの勉強",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
console.log(todo1 === todo2); // 比較結果は「false」一方で、次の comp2.ts の 第18行目
の出力は true
となります。
第13行目 の todo2 = todo1
で行われるのは、いわゆる「浅いコピー (Shallow
Copy) =
参照のコピー」であるため、そのような結果になります。この「浅いコピー」についてはPG1の第13回講語で丁寧に解説しているので再読してください。
export {};
import { Todo } from "./types";
const todo1: Todo = {
name: "TypeScriptの勉強",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
// ここで行なわれるのは「浅いコピー」、
// つまり「参照」のコピーであることに注意
const todo2 = todo1;
todo2.name = "COBOLの勉強をする";
todo2.priority = 3;
console.log(todo1 === todo2); // 比較結果は「true」既にPG1で、同様の内容を学んできていると思うので理解できると思いますが
comp2.ts の最後で
console.log(todo1.name); を実行したとき、その出力は
「COBOLの勉強をする」 となります。
6.3 オブジェクトの深い比較
参照の比較ではなく、オブジェクトのプロパティがすべて等しいかを比較するためには、つまり、深い比較
(Deep Comparison)
をするためには、カスタム比較関数を自作する必要があります
(ライブラリを使うという手段もありますが…)。以下に Todo
型オブジェクトの深い比較をするための関数 deepEqual
の実装例を示します。
import { Todo } from "../types";
export const deepEqual = (todo1: Todo, todo2: Todo): boolean => {
if (todo1 === todo2) {
return true;
}
if (
todo1.name === todo2.name &&
todo1.priority === todo2.priority &&
todo1.isDone === todo2.isDone &&
todo1.deadline.getTime() === todo2.deadline.getTime()
) {
return true;
}
return false;
};以上の deepEqual
を使用することで、todo1 と todo2
を同一とみなすような深い比較が可能となります。
export {};
import { Todo } from "./types";
import { deepEqual } from "./utils/deepEqual"; // 追加
const todo1: Todo = {
name: "TypeScriptの勉強",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
const todo2: Todo = {
name: "TypeScriptの勉強",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
console.log(todo1 === todo2); // 浅い比較 false
console.log(deepEqual(todo1, todo2)); // 深い比較 true実際に utils/deepEqual.ts
を実装して実験してください。
6.4 三項演算子
React開発では、条件演算子 (三項演算子) も頻繁に使われるので覚えておいてください。条件演算子の基本構文は次のようになります。
条件 ? 真の場合の値 : 偽の場合の値
上記の 条件
の部分には「真偽値の変数」や「各種比較演算子を使った式」を与えます。if
構文を使うよりも短く簡潔に記述ができます。以下に例を示します。
export {};
import { Todo } from "./types";
const todo1: Todo = {
name: "TypeScriptの勉強",
priority: 3,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
const state = todo1.isDone ? "【済】" : "【未】"; // 条件演算子
console.log(`${state}${todo1.name}`);React開発では、以下のようにオブジェクトの状態によって適用する CSS (画面上の装飾) を切り替えるために 条件演算子 (三項演算子) がよく使用されます。
(参考) 上記のコードの処理と完全一致しているわけではないので注意してください。
7 Reactにおける状態 (オブジェクト) の変更の検知 ~概要~
Reactでは「極めて大雑排に言えば、「オブジェクト」の状態が変更されたことを検知してライブラリ (React) が自動で画面を書き換える」ということが行われます (画面=DOM (Document Object Model)。
ここでのオブジェクトとは、例えば、ここまで何度も登場している
todo
です。そのオブジェクトの「状態が変更された」とは、例えば
name や isDone などの プロパティ
(属性) の変更 を意味します。
オブジェクトのプロパティの変更は、以下 (第15行目・第16行目) のように行なうことができます。
export {};
import { Todo } from "./types";
import { printTodo } from "./utils/printTodo";
const todo1: Todo = {
name: "TypeScriptの勉強",
priority: 3,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
console.log(`■ 状態変更前`);
printTodo(todo1);
todo1.name = "COBOLの勉強をする"; // プロパティの変更
todo1.priority = 1; // プロパティの変更
console.log(`■ 状態変更後`);
printTodo(todo1);実行結果は以下のようになります。確かに 第15行目 と 第16行目 の操作でプロパティが変更されていることが分かると思います。
■ 状態変更前
(優先度: 3) TypeScriptの勉強 期日: 2024/10/11 09:45
■ 状態変更後
(優先度: 1) COBOLの勉強をする 期日: 2024/10/11 09:45
しかし、極めて重要なポイントとして、上記のような操作でオブジェクトのプロパティを変更しても、Reactは オブジェクトの状態に変更があったことを検知してくれません。つまり、オブジェクトを変更しても、それを反映するように画面の更新 (=再レンダリング) をしてくれません😭。
Reactがオブジェクトの状態変更を検知しない理由は「Reactはオブジェクトの「参照」が変更されたときに、「オブジェクトが変更された」と検知・判断して画面の再レンダリングするという仕組みになっている
(重要)」ためです。さきほどの6.2
オブジェクトの比較 の comp2.ts
で示したように、= でコピーをしても、あるいは
プロパティを変更しても「参照」は変化しません。
7.1 Reactが変更を検知可能なオブジェクトの生成
Reactが変更を検知できるようにオブジェクトを生成する方法を解説します。これは、React開発において 特に重要な操作 となってくるので、しっかりと覚えておいてください。
まずは、次のように新たにオブジェクトを生成することで、オリジナル
(todo) とは 参照が異なるオブジェクト
(updatedTodo) を生成できます。
export {};
import { Todo } from "./types";
const todo: Todo = {
name: "TypeScriptの勉強",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};
// Reactの状態管理に適した
// todo とは参照は異なる updatedTodo を生成
const updatedTodo: Todo = {
name: "COBOLの勉強をする",// 変更
priority: 3, // 変更
isDone: todo.isDone, // todo の値を引き継ぐ
deadline: todo.deadline, // todo の値を引き継ぐ
};
// todo と updatedTodo のtodo の値を参照が「異なること」を確認
console.log(todo !== updatedTodo); // true であれば OKただし、多数のプロパティを持ったオブジェクトについて上記の方法は非常に冗長になります。例えば20個のプロパティを持ったオブジェクトについて、1個のプロパティだけを変更する場合でも、20個のプロパティを列挙する必要があります (コードの可読性が低下します)。
そのようなときに、次のような スプレッド構文 が利用されます。
スプレッド構文は、オブジェクトのプロパティを展開して新しいオブジェクトに組み込む強力な機能です。これにより、元のオブジェクトのプロパティをコピーしつつ、特定のプロパティだけを変更するコードを短く書くことができます。
なお、スプレッド構文を使用する際、プロパティを記述する順序に注意してください。あとに記述するプロパティは、前のプロパティを上書きします。
上記の場合、priority は 3
に更新されますが、name は todo の値
(TypeScriptの勉強") で上書きされてしまいます。
7.1.1 定着確認
次のプログラムにつづけて、isDone が
true に変更されたオブジェクトを
updatedTodo に得よ。
ただし、Reactが todo との差異を検知可能なように
updatedTodo の参照は、todo
の参照とは異なるようにすること。また、スプレッド構文を使用して記述すること。
export {};
import { Todo } from "./types";
const todo: Todo = {
name: "TypeScriptの勉強",
priority: 1,
isDone: false,
deadline: new Date(2024, 9, 11, 9, 45),
};8 授業時間外学習
- 本科目は「学修単位科目」です。今回の講義内容
+アルファ に関して 4時間相当の授業時間外学習
に取り組んでください。疑問点や不明点などを「生成AI」で調べて深堀りしたり、C言語やPythonプログラムを
TypeScript に移植したりすることをお勧めします。
- 次回の授業では「配列」について取り上げ、
mapやfilterなどの 配列操作メソッド (高階関数) を扱います。これらは React で頻度に使われるものになります。予習することを強く推奨します。 - YouTube検索: TypeScript map
- 次回の授業では「配列」について取り上げ、
- 次回の授業のはじめに「小テスト」を実施します。筆記用具を持参してください。