Denoに今後導入される新機能（2021秋ver）

## リリーススケジュール

- 2021年10月12日: Deno1.15のリリース
- 2021年11月16日: Deno1.16のリリース
- 2021年12月16日: Deno1.17のリリース [TypeScript4.5]
- 2022年1月20日: Deno1.18のリリース
- 2022年2月17日: Deno1.19のリリース

Denoのリリーススケジュールは基本的にv8のアップデート周期（4週間）と一致するようになっています。
11月に予定されていたDeno2.0は、来年に延期されました。


## Denoに今後導入される新機能

[前回の記事](https://qiita.com/access3151fq/items/9ae02922723be2db199f)から大分間が空いてしまいました…
以下に挙げるのは、導入される方向で議論が進んでいるものです。タイトルでは秋verと銘打ってはいるものの、進捗状況次第では導入が来年以降に持ち越されることもあり得ます。
また、ここで取り上げるのはほんの一部です。詳しい変更内容は各リリースのリリースノートを参照してください。

#### Node.js互換モード

denoにNode.js互換モードが導入されます。
これまで、Node.js向けライブラリの類は[esm.sh](https://esm.sh)などの3rd party CDNを利用することで、Denoからも利用できました。しかし、アプリケーション（サーバー等、ライブラリを使う側のコード）はDenoへの移行手段がありませんでした。Node.js互換モードは、こうした既存のコードベースをDenoに移行するための手段として開発されています。

Node.js互換モードを使うには、実行時に`--compat`フラグを設定することで使用できます。

```shell
> deno run --compat --unstable ./main.ts
```

まだ実験的な扱いであり、`--unsable`フラグも必要です。
フラグ下では、`require`、`node_modules`と`package.json`のサポート、node組み込みライブラリのpolyfillの差し込みなどが行われます。
今のところpolyfillが途中なため、一部のモジュールのみ動作します。現時点ではESLintやExpressが動くようになったという状況で、今後はvite、MongoDBドライバー、Mocha、Next.jsなどが動くことを目指してpolyfillを進めていくようです。

この機能はあくまでNode.jsからの移行のためであり、新しいプロジェクトを互換モードで開始する必要はなく、(エコシステム上)移行が十分に進んだら互換モードを削除する方針とのこと。

関連：[#12108](https://github.com/denoland/deno/discussions/12108)、[#12295](https://github.com/denoland/deno/issues/12295)、[#12577](https://github.com/denoland/deno/issues/12577)

#### deno deployの正式提供

[Deno Deployは、JavaScript、TypeScript、および WebAssembly を世界中のエッジで実行する分散システムです 。](https://deno.com/deploy/)

以下のような特徴があります。

- 例えばCloudFront Functionsがリダイレクト等の軽い処理を実行時間制限付きで行うのに対し、deno deployはメインのアプリケーションを全てエッジで実行する
- deno CLIで利用できるAPIと互換性があり、ローカル開発をDeno CLIで行うことができる
- GitHub連携を行うとGitHubリポジトリのファイルをローカルファイルのように扱うことができる
- サーバーの負荷に応じてサーバーが複数建ち、並列でリクエストを捌くことができる
- 日本では、東京リージョンと大阪リージョンが存在
- playgroundがある https://dash.deno.com/playground/my-server-example
- 現在ベータリリース中（正式提供は~~2021年第4四半期~~2022年上半期に予定）

今後のアップデートでは、正式リリースに向けてキャッシュ機能が追加される予定です。
また、CLIとの相互運用性、より良い開始フローにも対応していくとのこと。

[deno deployのissueレポート用リポジトリ](https://github.com/denoland/deploy_feedback)によると、長期的には、[定期実行](https://github.com/denoland/deploy_feedback/issues/122)や[ストレージ](https://github.com/denoland/deploy_feedback/issues/110)などのサポートも検討されているようです。

#### TypeScript 4.5

Deno1.17にてTypeScript4.5が導入されます。

TypeScript4.5によって、以下の機能が利用可能になります。

- インポートアサーション
- プライベートフィールドの人間工学的ブランドチェック（`#foo in obj`構文）
- `.mts` `.cts`のサポート
- `Awaited`ユーティリティ型
- …他

詳しくはTS4.5の[リリースノート](https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/)を参照してください。

また、TSがインポートアサーションに対応する事によって、DenoにJSONインポートのサポートが追加されます。

#### deno.jsonの強化

[deno.json（deno設定ファイル）](https://qiita.com/access3151fq/items/7aa44ee69b4a5ff867c7)にはフォーマッタやリンターの設定、TSのcompilerOptionを書くことができます。将来的にこれを拡張して、import-map、`--allow`フラグ、タスクランナーを設定できるようにすることが検討されています。

現在検討されている構文は以下のようなものです。

```jsonc:deno.jsonc
// 当該issueから引用
{
  "compilerOptions": { /* tsconfigの内容 */},
  "imports": {
    // import-mapの内容
    "lodash": "https://esm.sh/lodash",
    "fs": "https://deno.land/std/node/fs.ts"
  },
  "permissions": {
    // 権限フラグの設定
    "allow-all": true,
    "allow-env": true,
    "allow-hrtime": false,
    "allow-read": [ ".", "/tmp" ],
    "allow-write": ".",
    "allow-net": "deno.land,nest.land"
  },
  "tasks": {
    // タスクランナー
    "run": "./mod.ts",
    "build": "--allow-read --allow-write ./build.ts",
    "lint": "src/*.ts",
    "test": {
      "args": "--unstable",
      "permissions": { /*権限フラグの設定*/ },
    }
  }
}
```

また、deno.jsonはコマンドの`--congig`フラグで指定する必要がありますが、対象ディレクトリから自動で読み取るようにすることも検討されています。

毎回コマンドで権限を設定するのは面倒なので、早く導入されて欲しい所です。タスクランナーはpackage.jsonで設定するnpmスクリプトに近いですね。

関連：[#3179](https://github.com/denoland/deno/issues/3179)、[#12763](https://github.com/denoland/deno/issues/12763)、[#12764](https://github.com/denoland/deno/issues/12764)、[#12800](https://github.com/denoland/deno/issues/12800)、[#11907](https://github.com/denoland/deno/discussions/11907)

#### dnt

dntはdeno向けモジュールをNode.js向けに変換するツールです。

https://github.com/denoland/dnt

さきほど紹介したNode.js互換モードは、Node.js向けに書いたコードをDenoで使うためのものでした。dntはその逆で、Deno向けに書いたコードをNode.jsで使うための物です。
現在は、Denoの組み込み関数をNode.jsでpolyfillする作業中のようです。

#### deno.landからブラウザ向けのモジュール配信

ブラウザから直接[deno.land/std](https://deno.land/std)や[deno.land/x](https://deno.land/x)のモジュールをimportできるようにするという提案が出ています。
現在でもJavaScriptで書かれたモジュールはブラウザからimport可能ですが、TypeScriptもJavaScriptに変換された上で配信されるようになるため、標準ライブラリなどのtsファイルもブラウザにimportできるようになります。
なおJSに変換されるのはブラウザからアクセスされた時だけで、Deno上ではこれまで通りTypeScriptを使うことができます。

関連：[dotland#1902](https://github.com/denoland/dotland/pull/1902)

#### signal系APIの変更・安定

1. `Deno.Signal`をenumから文字列のUnion Typeに変更

    これまで`Deno.Signal`はTypeScriptのEnumによって実装されていました。OSごとに複数のemumを管理するのは冗長だということで、単純な文字列のUnion Typeに変更されました。
    v1.14.0で導入されました。
    関連：[#11900](https://github.com/denoland/deno/issues/11900)
1. `Deno.addSignalListener`の追加
    `Deno.addSignalListener`は、Signalが発生した時に実行する関数を設定する機能です。これまでは`Deno.Signal`を`for-await-of`で待ち受けるというAPIでしたが、これがイベントベースの形式に変更されました。合わせて標準ライブラリのsignals/onSignalも非推奨化・削除されます。
    v1.16.0で導入されました。

    ```ts:v1.15.3以前
   for await (const _ of Deno.signal(Deno.Signal.SIGINT)) {
      console.log("SIGINT");
    }
    ```
    ```ts:v1.16.0以降
    Deno.addSignalListener("SIGINT", ()=>console.log("SIGINT"));
    ```
    関連：[#11158](https://github.com/denoland/deno/issues/11158)、[deno_std#1644](https://github.com/denoland/deno_std/pull/1644)

#### `--no-check=remote`フラグの導入

これまでTypeScriptの型チェックは、全てのファイルをチェックするか全くチェックしないかの2択でした。このフラグが導入されると、「外部の依存関係のコードは型チェックしない」という事が可能になります。

関連：[#11970](https://github.com/denoland/deno/issues/11970)、[#12766](https://github.com/denoland/deno/pull/12766)


# Deno2.0で導入予定の新機能

11月に予定されていたDeno2.0ですが、Node.js互換モードの完成まで延期されました。
ここでは、元々11月に予定されていた2.0リリースで入る予定だった機能を解説します。
2.0はメジャーリリースのため、破壊的変更が入ります。

参考：[2.0のダッシュボード](https://github.com/orgs/denoland/projects/5)、[2.0リリースプラン](https://github.com/denoland/deno/issues/12110)

### 新機能

#### 新しいサブプロセスAPI

現在の`Deno.run`に代わる新しいサブプロセスAPIとして、`Deno.Command`が導入されます。
[型定義](https://github.com/denoland/deno/pull/11618/files#diff-37043c904ab97dbfe6b6660102ef01f47b56b6579bd90102fda38423a44f0383)を見ると、以下のような使用方になると思われます。

```ts:使用方（推測）
const res = new Deno.Command("cat", { args: ["./foo.txt"] }).outut();
console.log(res) // catコマンドの出力
```

これは後方互換性が無い変更ではないなので、2.0より前のリリースで入るかもしれません。

関連：[#11016](https://github.com/denoland/deno/issues/11016)、[#5501](https://github.com/denoland/deno/issues/5501)、[#11618](https://github.com/denoland/deno/issues/11618)

#### デフォルトでロックファイルを使用する

`deno run`コマンドの`--lock`フラグを使うと、依存モジュールのチェックサムを検証することができます。この動作がデフォルトになります（`--lock`フラグが無くてもロックファイルを使用する）。

関連：[#11971](https://github.com/denoland/deno/issues/11971)

#### 動的import/Workerの権限をチェックする`--allow-import=<allow_list>`フラグ

現在、動的importやWorkerの作成には--allow-readフラグや--allow-netフラグが必要です。これらのフラグは`allow-read=./foo/,./bar/`等の構文で許可を与える範囲を制限することができますが、importするファイル全てを指定する必要があるため、フラグが長くなってしまうという欠点があります。`--allow-import`フラグを導入することで、エントリポイントに対してimportが許可されているディレクトリを指定することができるようになります。

関連：[#8266](https://github.com/denoland/deno/issues/8266)

#### NotCapableエラー

ファイルの読み書き時にPermissionDeniedエラーが発生することがありますが、これの原因は

- Deno自体のサンドボックス機構によって発生したもの（--allowフラグの付け忘れ）
- OS側の権限不足によって発生したもの（chmodする必要がある）

の2通りあり得ます。どちらによってエラーが発生したのかを区別するため、新たに`NotCapable`エラーを導入することが検討されています。

関連：[#7394](https://github.com/denoland/deno/issues/7394)


### TypeScript関連

#### 実行時の型チェックをオプションにする

現在は、実行時には毎回型チェックが走っています（厳密にいうと毎回チェックされているわけではなく、結果はキャッシュされています）。実行時の型チェックを無効にするには`--no-check`フラグを付ける必要があります。
Deno2.0では、フラグ無しの時は従来の`--no-check`フラグ付きと同じ動作になり、型チェックを行いたい時は`--check`フラグを付けなければいけないようになります。
また、合わせて型チェックのみを行う`deno check`コマンドも導入されます。

デフォルトでは型チェックを行わなくなることに対して、賛成派の意見として以下のようなものを見かけました。（discord等で見かけただけのやつもあります）

- 型チェックが遅い
- 初めて使う人にとってはTypeScriptのエラーが分かりにくい
- IDEを使っていれば、型チェックで出るエラーはエディタ上に表示される
- 今後のWeb標準との互換のため
- （Next.jsなど）ESbuild・swcを使用する他のツールは型チェックをしないのが主流になってきている

「今後のWeb標準との互換のため」というのは、今後JavaScriptの仕様にTypeScript構文(またはそれに準ずるもの)が導入されることを見越してのようです。JSの仕様にTS構文が入った場合、ランタイムがコードを実行する時には型チェックを行わないだろうという見方が大きく、そういった今後の仕様に合わせるという意味で型チェックをしないという事です。

一方、反対意見も出ています。

- 型チェックはキャッシュされるため、遅さを感じるのは初回実行時だけ
- TSの型エラーが不要な時はJSを使えばいい
- 全員がIDEを使っているわけではない

このように反対意見が出ているものの、一応この変更を入れる方向で動いているようです。
合わせて`deno test --no-run`コマンドも削除されます。このコマンドは型チェックだけを行うコマンドでしたが、`--no-check`がデフォルトになると何も実行しないコマンドになってしまうので削除されます。
CI等への影響を考慮して2.0での導入が予定されています。

関連：[#8549](https://github.com/denoland/deno/discussions/8549)、[#11340](https://github.com/denoland/deno/issues/11340)、[#11810](https://github.com/denoland/deno/pull/11810)、[#11786](https://github.com/denoland/deno/issues/11786)、[#11915](https://github.com/denoland/deno/issues/11915)

#### デフォルトのtsconfigのみ使用可能にする

tsconfig.jsonのcompilerOptionはコマンドの`--config`フラグで指定できます。しかし、複数のライブラリがそれぞれ異なるtsconfigを使用している場合はどうでしょうか。ライブラリのユーザーが指定できるのは1つのtsconfigだけなので、異なるtsconfigを持つライブラリを同時に使用できません。
このように、人々が各々のtsconfigを使って開発するとモジュール間に分断が生まれるため、デフォルトのtsconfig以外を使用不可にしようという提案が行われています。
ただし、

- デフォルトのtsconfigには何を指定すべきか
- 将来的にデフォルトのtsconfigが変わった場合、移行のために変更前のtsconfigを指定できないと困るのではないか

といった点を検討中なため、まだ導入が確定しているわけではなさそうです。
特に、依存関係の奥深くにtsconfig由来のエラーが出ている場合に対処のしようが無いので、困ってしまいます。この問題に対処するため、次項のような提案も出ています。

関連：[#7732](https://github.com/denoland/deno/discussions/7732)、[#12111](https://github.com/denoland/deno/issues/12111)

#### 外部コードのTypeScript診断を無視する

外部の依存関係の中からTSエラーが出ている場合、これをユーザーが修正するのは困難です。特に、Deno本体でデフォルトのtsconfigを更新するとライブラリからエラーが出てしまい、更新ができないという問題が実際に発生しています（[useUnknownInCatchVariables](https://github.com/denoland/deno/pull/12643#issue-1043814345)の時など）。
こうした状況に対処するため、外部の依存関係から発生したTSエラーを無視するようにするという提案が出ています。
Deno1.17で`--no-check=remote`フラグが導入され、2.0でこのフラグを指定した状態がデフォルトになります。

関連：[#11970](https://github.com/denoland/deno/issues/11970)、[#12766](https://github.com/denoland/deno/pull/12766)

#### JSXファクトリ関数を`React.createElement`から`h`に変更

JSXをトランスパイルする時に、どの関数にトランスパイルするかを表すのがJSXファクトリ関数です。現在のデフォルトは`React.createElement`ですが、そもそもDenoではデフォルトがReactである必要はあまりないため、これを`h`に変更します。
既にdeno deployはデフォルトが`h`になっており、これと挙動を合わせる形となります。

関連：[#11186](https://github.com/denoland/deno/issues/11186)



### 非推奨 or 不要な機能の削除

#### Deno.customInspectの削除

`Deno.customInspect`は、`Symbol.for("Deno.customInspect")`が導入される前に使われていたプロパティで、現在は非推奨になっています。2.0でこれを削除します。

関連：[#10929](https://github.com/denoland/deno/issues/10929)

#### `eval`コマンドの`--ts`フラグを削除する

既に非推奨になっている`eval`コマンドの`--ts`フラグが削除されます。削除後は`--ext=ts`フラグを使用する必要があります。

関連：[#12198](https://github.com/denoland/deno/pull/12198)

#### JSで実装されているio関数をDeno本体から標準ライブラリに移動する

Deno本体にある関数には、JSのみで実装されているものがあります。Denoの内部で実装するのはOSのシステムコールが必要なものに絞り、rustの呼び出しが不要なものは標準ライブラリから提供することで、ブラウザ互換性が向上します。
既に実装の移動は完了しており、非推奨扱いでDeno本体に残っている関数や型定義が2.0で削除されます。


関連：[#9795](https://github.com/denoland/deno/issues/9795)

#### ridを使用するDenoメソッドを削除する

`Deno.open`で開いたファイルハンドラからreadする方法は、直接`.read()`メソッドを呼ぶ方法と、`Deno.read(rid)`を使う方法の2種類あります。

```ts
const file = await Deno.open(new URL("./test.json", import.meta.url));
const buf = new Uint8Array(1);
file.read(buf); // パターン1
Deno.read(file.rid, buf); // パターン2
```
ridを直接操作する方法はあまり使われておらず、またバグの原因にもなるため、削除されます。
`Deno.read`以外に、`Deno.write`、`Deno.fsyncSync`、`Deno.fsync`、`Deno.fdatasyncSync`、`Data.fdatasync`、`Deno.flock`、`Deno.flockSync`、`Deno.funlock`、`Deno.funlockSync`も同様に削除されます。

関連：[#12107](https://github.com/denoland/deno/issues/12107)

<!--
#### --allow-hrtimeを削除
-->



### デフォルト値の変更

#### Worker内でデフォルトでDeno APIを有効にする

現在はデフォルトではWorker内でDeno APIを使うことはできません。使うためには、Workerの作成時に`{deno: true}`を指定します。

```ts
new Worker("./foo.js", {
  deno: true,  // これを指定するとWorker内でDeno APIを使うことができる
});
```

2.0ではこれがデフォルトで有効になり、無効化するためには`{deno: false}`を指定するようになります。


関連：[#8174](https://github.com/denoland/deno/issues/8174)

#### ProcessStatus.signalの引数をnumberからstringに変更

Deno.signal型がenumからstringのUnion型に変更されたのに合わせて、ProcessStatus.signalの引数がnumberからstringに変更されます。
ProcessStatusは`Deno.run()`で生成したサブプロセスのステータスを表す型で、既にstableな（=マイナーリリースで破壊的変更が無い）APIなので、2.0で変更されます。

関連：[#11912](https://github.com/denoland/deno/issues/11912)

#### `deno run`コマンドで拡張子が無いファイルを実行する場合、TypeScriptとして扱う

現在は拡張子が無いファイルはJavaScriptとして扱われています。これをTypeScriptとして扱うように変更します。

関連：[#12220](https://github.com/denoland/deno/issues/11220)


<!--
## その他

`Deno.Metrics`のリファクタリング
https://github.com/denoland/deno/issues/12109

## 導入されるか不明なもの

[?]FileとDeno.Fileが紛らわしい
https://github.com/denoland/deno/issues/12229

[?]`--format`フラグを導入する
https://github.com/denoland/deno/issues/11914

[?]`deno info`から`deno graph`を分割
https://github.com/denoland/deno/issues/10628

[?]`Deno.env.toObject()`の型定義を修正
https://github.com/denoland/deno/issues/10267

[?]`Deno.test`中の`console.log`の出力を改善する
https://github.com/denoland/deno/issues/10099

[?]Deno.errors名前空間をDeno名前空間に移動する
https://github.com/denoland/deno/issues/9646

[?]cliオプションをフラグとオプションに分割
https://github.com/denoland/deno/issues/8618

[?]`--allow-*`フラグや`--ignore`フラグにカンマを含むディレクトリとファイル名を指定可能にする
https://github.com/denoland/deno/issues/6553
https://github.com/denoland/deno/issues/9535

[?]`deno fmt`が`node_modules`フォルダや`.vscode`フォルダを無視するようにする
https://github.com/denoland/deno/issues/4459
https://github.com/denoland/deno/issues/11797
-->

## まとめ

上で紹介した以外にも新機能やバグ修正が盛んに行われています。特に~~第4四半期~~来年上半期に正式提供とされているdeno deployは、手軽にサーバーを建てる手段として使っていきたいです。

※内容に間違いがある場合はコメントで指摘してもらえると嬉しいです。