Skip to content

Commit b730804

Browse files
committed
typescriptのドキュメントを追加、実行環境修正
1 parent 289391b commit b730804

File tree

12 files changed

+2076
-9
lines changed

12 files changed

+2076
-9
lines changed

app/pagesList.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,21 @@ export const pagesList = [
5656
{ id: 10, title: "非同期処理②: Async/Await" },
5757
],
5858
},
59+
{
60+
id: "typescript",
61+
lang: "TypeScript",
62+
description: "にゃー",
63+
pages: [
64+
{ id: 1, title: "TypeScriptへようこそ" },
65+
{ id: 2, title: "基本的な型と型推論" },
66+
{ id: 3, title: "オブジェクト、インターフェース、型エイリアス" },
67+
{ id: 4, title: "関数の型定義" },
68+
{ id: 5, title: "型を組み合わせる" },
69+
{ id: 6, title: "ジェネリクス" },
70+
{ id: 7, title: "クラスとアクセス修飾子" },
71+
{ id: 8, title: "非同期処理とユーティリティ型" },
72+
],
73+
},
5974
{
6075
id: "cpp",
6176
lang: "C++",

app/terminal/editor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export function EditorComponent(props: EditorProps) {
8989
const { files, writeFile } = useEmbedContext();
9090
const code = files[props.filename] || props.initContent;
9191
useEffect(() => {
92-
if (!files[props.filename]) {
92+
if (!files[props.filename] && props.initContent) {
9393
writeFile({ [props.filename]: props.initContent });
9494
}
9595
}, [files, props.filename, props.initContent, writeFile]);

app/terminal/page.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ interface SampleConfig {
5353
replInitContent?: string; // ReplOutput[] ではない。stringのパースはruntimeが行う
5454
editor: Record<string, string> | false;
5555
exec: string[] | false;
56+
readonlyFiles?: string[];
5657
}
5758
const sampleConfig: Record<RuntimeLang, SampleConfig> = {
5859
python: {
@@ -65,8 +66,7 @@ const sampleConfig: Record<RuntimeLang, SampleConfig> = {
6566
},
6667
ruby: {
6768
repl: true,
68-
replInitContent:
69-
'irb(main):001:0> puts "Hello, World!"\nHello, World!',
69+
replInitContent: 'irb(main):001:0> puts "Hello, World!"\nHello, World!',
7070
editor: {
7171
"main.rb": 'puts "Hello, World!"',
7272
},
@@ -83,10 +83,12 @@ const sampleConfig: Record<RuntimeLang, SampleConfig> = {
8383
typescript: {
8484
repl: false,
8585
editor: {
86-
"main.ts":
86+
// main.tsにすると出力ファイルがjavascriptのサンプルと被る
87+
"main2.ts":
8788
'function greet(name: string): void {\n console.log("Hello, " + name + "!");\n}\n\ngreet("World");',
8889
},
89-
exec: ["main.ts"],
90+
exec: ["main2.ts"],
91+
readonlyFiles: ["main2.js"],
9092
},
9193
cpp: {
9294
repl: false,
@@ -131,6 +133,15 @@ function RuntimeSample({
131133
{config.exec && (
132134
<ExecFile filenames={config.exec} language={lang} content="" />
133135
)}
136+
{config.readonlyFiles?.map((filename) => (
137+
<EditorComponent
138+
key={filename}
139+
language={getAceLang(lang)}
140+
filename={filename}
141+
initContent=""
142+
readonly
143+
/>
144+
))}
134145
</div>
135146
);
136147
}

app/terminal/typescript/runtime.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import type { CompilerOptions } from "typescript";
3+
import type { ScriptTarget, CompilerOptions } from "typescript";
44
import type { VirtualTypeScriptEnvironment } from "@typescript/vfs";
55
import {
66
createContext,
@@ -14,7 +14,10 @@ import { useEmbedContext } from "../embedContext";
1414
import { ReplOutput } from "../repl";
1515
import { RuntimeContext } from "../runtime";
1616

17-
export const compilerOptions: CompilerOptions = {};
17+
export const compilerOptions: CompilerOptions = {
18+
lib: ["ESNext", "WebWorker"],
19+
target: 10 satisfies ScriptTarget.ES2023,
20+
};
1821

1922
const TypeScriptContext = createContext<{
2023
init: () => void;
@@ -78,7 +81,12 @@ export function TypeScriptProvider({ children }: { children: ReactNode }) {
7881
}
7982

8083
export function useTypeScript(jsEval: RuntimeContext): RuntimeContext {
81-
const { init, tsEnv } = useContext(TypeScriptContext);
84+
const { init: tsInit, tsEnv } = useContext(TypeScriptContext);
85+
const { init: jsInit } = jsEval;
86+
const init = useCallback(() => {
87+
tsInit();
88+
jsInit?.();
89+
}, [tsInit, jsInit]);
8290

8391
const { writeFile } = useEmbedContext();
8492
const runFiles = useCallback(
@@ -129,6 +137,10 @@ export function useTypeScript(jsEval: RuntimeContext): RuntimeContext {
129137
)
130138
);
131139

140+
for (const filename of Object.keys(files)) {
141+
tsEnv.deleteFile(filename);
142+
}
143+
132144
console.log(emitOutput);
133145
const jsOutputs = jsEval.runFiles(
134146
[emitOutput.outputFiles[0].name],
@@ -149,5 +161,5 @@ export function useTypeScript(jsEval: RuntimeContext): RuntimeContext {
149161
}
150162

151163
function getCommandlineStr(filenames: string[]) {
152-
return `tsc ${filenames.join(" ")}`;
164+
return `npx tsc ${filenames.join(" ")} && node ${filenames[0].replace(/\.ts$/, ".js")}`;
153165
}

public/docs/typescript-1.md

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# 第1章: TypeScriptへようこそ
2+
3+
JavaScriptの経験がある皆さん、TypeScriptの世界へようこそ。
4+
この章では、TypeScriptがどのような言語であるか、なぜ現代のWeb開発のスタンダードとなっているのかを理解し、実際に開発環境を整えて最初のコードを実行するところまでを学びます。
5+
6+
## TypeScriptとは?
7+
8+
TypeScriptは、Microsoftによって開発されているオープンソースのプログラミング言語です。一言で言えば、**「型(Type)を持ったJavaScript」**です。
9+
10+
重要な特徴は以下の通りです:
11+
12+
* **JavaScriptのスーパーセット(上位互換):** すべての有効なJavaScriptコードは、有効なTypeScriptコードでもあります。つまり、今日から既存のJS知識をそのまま活かせます。
13+
* **静的型付け:** JavaScriptは実行時に変数の型が決まる「動的型付け言語」ですが、TypeScriptはコンパイル時(コードを書いている途中やビルド時)に型をチェックする「静的型付け言語」としての性質を持ちます。
14+
* **コンパイル(トランスパイル):** ブラウザやNode.jsはTypeScriptを直接理解できません。TypeScriptコンパイラ(`tsc`)を使って、標準的なJavaScriptファイルに変換してから実行します。
15+
16+
## なぜTypeScriptか?
17+
18+
「わざわざ型を書くのは面倒だ」と感じるかもしれません。しかし、中〜大規模な開発においてTypeScriptは以下の強力なメリットを提供します。
19+
20+
1. **型安全性(バグの早期発見):**
21+
`undefined` のプロパティを読み取ろうとしたり、数値を期待する関数に文字列を渡したりするミスを、コードを実行する前にエディタ上で警告してくれます。
22+
2. **強力なエディタサポート:**
23+
VS Codeなどのエディタでは、型情報に基づいた正確なコード補完(IntelliSense)が効きます。APIの仕様をドキュメントで調べなくても、ドット`.`を打つだけで利用可能なメソッドが表示されます。
24+
3. **リファクタリングの容易さ:**
25+
変数名や関数名を変更する際、型情報があるおかげで、影響範囲を自動的に特定し、安全に一括置換できます。
26+
27+
## 環境構築
28+
29+
それでは、実際にTypeScriptを動かす環境を作りましょう。
30+
31+
### プロジェクトの作成とTypeScriptのインストール
32+
33+
今回はローカル環境にTypeScriptをインストールする方法を採用します。適当なディレクトリを作成し、ターミナルで以下のコマンドを実行してください。
34+
35+
※あらかじめ [Node.js](https://nodejs.org/) がインストールされていることを前提とします。
36+
37+
```bash
38+
# プロジェクトフォルダの作成と移動
39+
mkdir ts-tutorial
40+
cd ts-tutorial
41+
42+
# package.jsonの初期化
43+
npm init -y
44+
45+
# TypeScriptのインストール(開発用依存関係として)
46+
npm install --save-dev typescript
47+
```
48+
49+
インストールが完了したら、バージョンを確認してみましょう。
50+
51+
```bash
52+
npx tsc --version
53+
# Output: Version 5.x.x (バージョンは時期によります)
54+
```
55+
56+
## 最初のTypeScript
57+
58+
いよいよ最初のTypeScriptコードを書いてみましょう。
59+
60+
### コードの記述
61+
62+
エディタで `hello.ts` というファイルを作成し、以下のコードを記述します。
63+
JavaScriptと似ていますが、変数宣言の後ろに `: string` という「型注釈(Type Annotation)」が付いている点に注目してください。
64+
65+
```ts:hello.ts
66+
// 変数messageにstring型(文字列)を指定
67+
const message: string = "Hello, TypeScript World!";
68+
69+
// 数値を渡そうとするとエディタ上でエラーになります(後ほど解説)
70+
console.log(message);
71+
```
72+
73+
### コンパイルと実行
74+
75+
このままではNode.jsで実行できないため、JavaScriptにコンパイルします。
76+
77+
```bash
78+
npx tsc hello.ts
79+
```
80+
81+
エラーが出なければ、同じフォルダに `hello.js` というファイルが生成されています。中身を確認すると、型注釈が取り除かれた普通のJavaScriptになっているはずです。
82+
83+
生成されたJSファイルをNode.jsで実行します。
84+
85+
```ts-exec:hello.ts
86+
Hello, TypeScript World!
87+
```
88+
89+
これがTypeScript開発の基本的なサイクル(記述 → コンパイル → 実行)です。
90+
91+
このウェブサイトでは上のようにコードを編集して実行ボタンを押すとコンパイルと実行を行うことができる環境を埋め込んでいます。
92+
93+
またコンパイル後のjsファイルの内容も以下のように確認できます。
94+
95+
```js-readonly:hello.js
96+
"use strict";
97+
// 変数messageにstring型(文字列)を指定
98+
const message = "Hello, TypeScript World!";
99+
// 数値を渡そうとするとエディタ上でエラーになります(後ほど解説)
100+
console.log(message);
101+
```
102+
103+
## tsconfig.json: コンパイラの設定
104+
105+
毎回 `npx tsc hello.ts` のようにファイル名を指定するのは手間ですし、プロジェクト全体の設定も管理しづらくなります。そこで、`tsconfig.json` という設定ファイルを使用します。
106+
107+
以下のコマンドで初期設定ファイルを生成します。
108+
109+
```bash
110+
npx tsc --init
111+
```
112+
113+
生成された `tsconfig.json` には多くの設定項目がありますが、基本として以下の設定が有効(コメントアウトされていない状態)になっているか確認してください。
114+
115+
```json
116+
{
117+
"compilerOptions": {
118+
"target": "es2016", /* コンパイル後のJSのバージョン */
119+
"module": "commonjs", /* モジュールシステム */
120+
"strict": true, /* 厳格な型チェックを有効にする(重要) */
121+
"esModuleInterop": true, /* CommonJSモジュールとの互換性 */
122+
"forceConsistentCasingInFileNames": true, /* ファイル名の大文字小文字を区別 */
123+
"skipLibCheck": true /* 定義ファイルのチェックをスキップ */
124+
}
125+
}
126+
```
127+
128+
### 設定ファイルを使ったコンパイル
129+
130+
`tsconfig.json` があるディレクトリでは、ファイル名を指定せずに以下のコマンドだけで、ディレクトリ内のすべてのTypeScriptファイルが設定に基づいてコンパイルされます。
131+
132+
```bash
133+
npx tsc
134+
```
135+
136+
> **Note:** `strict: true` はTypeScriptの恩恵を最大限に受けるために非常に重要です。このチュートリアルでは常にこの設定が有効であることを前提に進めます。

0 commit comments

Comments
 (0)