VS Code(Visual Studio Code)でTypeScriptを実行してみる

f:id:ts0818:20211229161238j:plain

zuuonline.com

GDPREU一般データ保護規則EUではすでに導入済み(※1 ))が、各国で導入され始めれば、GAFAクラウドなども、各国に置かなくてはならなくなる。

GAFAの限界? サーバーの各国配置が命取りになっているワケ | ZUU online

(※1)GDPR……欧州議会欧州理事会および欧州委員会が、EU内のすべての個人のために、データ保護の強化・統合を意図している規則。EU域外への個人情報の輸出も対象としている。

GAFAの限界? サーバーの各国配置が命取りになっているワケ | ZUU online

もう一つの不安点は、BEPS(税源浸食と利益移転)だ。BEPSに関しては一気に規制が進んでおり、国際的な最終課税15%で合意された。このミニマム課税15%によって、GAFAが使ってきたこれまでの租税回避地タックスヘイブン)に本社や知的財産権を持つ部門を置き、そこに利益を集中させて各国に税金を払わない体制は壊れていく。

GAFAの限界? サーバーの各国配置が命取りになっているワケ | ZUU online

⇧ 各種クラウドサービスが値上がりとかしないかが不安ですな...

今回も「TypeScript」についてです、「VS CodeVisual Studio Code)」のほうも調査してます。

レッツトライ~。

プロジェクトのフォルダ構成はどうする?

なんか、Javaとかだと、「Maven」や「Gradle」といった「ビルドツール」で良しなに「src/main/java」とかいったディレクトリ構造を作ってくれるんだけど、「TypeScript」ってそのあたりどうなってるんだろう?

ドキュメントによりますと、

www.typescriptlang.org

An Example Project

Let’s look at a fairly normal program and see how project references can help us better organize it. Imagine you have a project with two modules, converter and units, and a corresponding test file for each:

/
├── src/
│   ├── converter.ts
│   └── units.ts
├── test/
│   ├── converter-tests.ts
│   └── units-tests.ts
└── tsconfig.json

https://www.typescriptlang.org/docs/handbook/project-references.html

⇧ というようなサンプルは載ってるんだけど、なんとなく、ディレクトリ構造を作ってくれるような便利な方法は紹介してくれてないところを見ると、自分で頑張って、「フォルダ」を作成する感じになる模様。

というわけで、頑張って「フォルダ」を作ります。

f:id:ts0818:20211228200902p:plain

とりあえず、「src」「test」「dist」の3つのフォルダを作成しておきました。

f:id:ts0818:20211228205053p:plain

基本的には、「TypeScript」単独で使うことはほとんどなく、「Vue.js」「React」「Angular」といった「JavaScriptフレームワーク」と併用することになることが多いらしいので、「TypeScript」プロジェクトのディレクトリ構造というよりは、利用する「JavaScriptフレームワーク」に合わせたプロジェクトのディレクトリ構造にする感じになるみたいね。

dev.to

⇧ 上記サイト様も、大枠は、「src」「test」の2つのディレクトリ構造になっている感じですね。

TypeScriptの型はどれだけあるのか?

公式のドキュメントでOverviewとか載っけてくれてないので、何とも言えないのだけど、

tech-en.netlify.app

⇧ 上記サイト様によりますと、上図のようなイメージらしい。

ちなみに、公式のドキュメントによる「型」の説明っぽいページは以下。

www.typescriptlang.org

⇧ なんか、カテゴライズされてなくて、ただ並べただけのように見えるので、混沌としてるように見えるけど、上記が全量なのかもいまいち判然としないというね...

JavaScript」の曖昧さを補完する目的の「型」であるのに、その全貌が曖昧模糊としちゃってるのは、どうなのよ?

日本語版のドキュメントによると、

typescript-jp.gitbook.io

まとめ

これで、ほとんどのJavaScriptコードに型アノテーションを付けることができるようになりました。これで、TypeScriptの型システムで使用可能なすべての機能の詳細を説明できます。

https://typescript-jp.gitbook.io/deep-dive/type-system

⇧ 一応、説明してるので全量っぽい書きっぷりのまとめになってますな。

ただ、

typescript-jp.gitbook.io

他のライブラリとかの「型」定義とかも作ってるらしく、それらを使う場合は、「npm」でインストールする必要があるみたい。

複数の「.ts」ファイルをどう扱うか?

というわけで、新しく「.ts」ファイルを作成して、コーディングしようとしてのっけからエラーに遭遇...

f:id:ts0818:20211228222116p:plain

f:id:ts0818:20211228222143p:plain

⇧ 何と言うことでしょう...

まさかの他のファイルで使ってる変数名が使えないだと!

どうやら、

techtechmedia.com

TypeScriptでとあるコードを記述すると、デフォルトでグローバル空間に追加されます。

【TypeScript】モジュールについての理解を深める-内部モジュール編-|TechTechMedia

⇧ デフォルトで「グローバル空間」で共有されてしまうという恐ろしい仕様、それが「TypeScript」ということらしい...そんなバナナ...

で、複数の「.ts」ファイルを扱う場合、どうすれば良いのよ?

teppeis.hatenablog.com

blog.uhy.ooo

osamtimizer.hatenablog.com

⇧ なんか、「JavaScript」の仕様的に、なかなか納得のいくような方法が出てないってことみたいですね、みんな渋々、現状の仕様の縛りの中で試行錯誤するしかない状況ではあるみたいですね。

ちなみに、「TypeScript」のドキュメントによると、

www.typescriptlang.org

Using Module

Modules also have a dependency on a module loader (such as CommonJs/Require.js) or a runtime which supports ES Modules. Modules provide for better code reuse, stronger isolation and better tooling support for bundling.

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html

It is also worth noting that, for Node.js applications, modules are the default and we recommended modules over namespaces in modern code.

https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html

⇧「Node.js」のアプリケーションを作ってる場合は、「Module」を使っておくのをお勧めしますということみたい。

まぁ、今回は、「namespace」を使ってみました。「lesson_type.ts」と「main.ts」ってファイルを作成しました。

f:id:ts0818:20211229155902p:plain

文字列の中身とかは、

cototama.com

⇧ 上記サイト様を参考にさせていただきました。

■C:\Users\Toshinobu\Desktop\soft_work\typescript_work\src\lesson_type.ts

export namespace ComExampleDemoType {
  // プリミティブ型
  let num: number = 123;
  console.log(num);
  let str: string = "hello, typescript";
  console.log(str);
  let bool: boolean = true;
  console.log(bool);

  // ■配列(Arrays)
  let boolArr: boolean[] = [];
  let boolValue: boolean;
  for (let index: number = 0; index < 10; index++) {
    if (index % 2 == 0) {
      boolValue = true;
    } else {
      boolValue = false;
    }
    boolArr.push(boolValue);
  }
  // 結果出力
  console.log(boolArr);

  let numList: Array<number> = [];
  for (let index: number = 0; index < 10; index++) {
    numList.push(index);
  }
  // 結果出力
  console.log(numList);

  // ■インターフェース(Interfaces)
  interface Crazy {
    new (): CrazyConstractor;
  }

  interface CrazyConstractor {}

  class CrazyClass implements CrazyConstractor {
    constructor() {
      return { hello: 123 };
    }
  }
  // Because
  const crazy = new CrazyClass();
  console.log(crazy);

  // ■インライン型アノテーション(Inline Type Annotation)
  var Crazy: {
    new (): CrazyConstractor;
  };

  var CrazyConstractor: {};

  class CrazyInlineClass implements CrazyConstractor {
    constructor() {
      return { hello: 123 };
    }
  }
  const crazyInline = new CrazyInlineClass();
  console.log(crazyInline);

  // ■any
  var power: any;
  power = "power of the people";
  console.log(power);

  var n: number;
  n = 1234567890;
  power = n;
  console.log(power);

  // ■nullとundefined
  var unknown: any;
  unknown = null;
  console.log(unknown);
  unknown = undefined;
  console.log(unknown);

  // ■:void
  function log(message: string): void {
    console.log(message);
  }
  log("さよならだけが人生だ");

  // ■ジェネリックス(Generics)
  function reverse<T>(items: T[]): T[] {
    var toreturn = [];
    for (let index: number = items.length - 1; index >= 0; index--) {
      toreturn.push(items[index]);
    }
    return toreturn;
  }

  var sample: number[] = [1, 2, 3, 4, 5, 6, 7];
  var reversedNumArr: number[] = reverse(sample);
  console.log(reversedNumArr);
  var strArr: string[] = [
    "一富士",
    "二鷹 ",
    "三茄子",
    "四扇",
    "五煙草",
    "六座頭",
  ];
  var reversedStrArr: string[] = reverse(reverse(strArr));
  console.log(reversedStrArr);

  // ■ユニオン型(Union Type)
  function formatCommandline(command: string[] | string) {
    var line = "";
    if (typeof command === "string") {
      line = command.split(",").join();
    } else {
      line = command.join(" ").trim();
    }
    console.log(line);
  }

  formatCommandline(`
    一粒万倍(いちりゅうまんばい)
    慶雲昌光(けいうんしょうこう)
    春山如笑(しゅんざんわらうがごとし)
    笑門来福(しょうもんらいふく)
    新春万福(しんしゅんばんぷく)
    千客万来(せんきゃくばんらい)
    前途有望(ぜんとゆうぼう)
    大願成就(たいがんじょうじゅ)
    長楽萬年(ちょうらくまんねん)
    伯楽一顧(はくらくいっこ)
    飛竜乗雲(ひりょうくもにのる)
    鳳鳴朝陽(ほうちょうようになく)
    無病息災(むびょうそくさい)
    和風慶雲(わふうけいうん)
    春光日々新(しゅんこうひびあらた)
    日日是好日(にちにちこれこうじつ)
    万物光輝生(ばんぶつこうきをしょうず)
    福寿海無量(ふくじゅかいむりょう)
    無心得良悟(むしんりょうごをう)
  `);

  // ■交差型(Intersection Type)
  function extend<T, U>(first: T, second: U): T & U {
    return { ...first, ...second };
  }
  const x = extend({ a: "hello" }, { b: 42 });
  console.log(x.a);
  console.log(x.b);

  // ■タプル型
  var nameNumber: [string, number];
  nameNumber = ["Jenny", 8675309];
  console.log(nameNumber);
  console.log(nameNumber[0]);
  console.log(nameNumber[1]);
  var [nameValue, numValue]: [string, number] = nameNumber;
  console.log(nameValue);
  console.log(numValue);

  // ■型エイリアス(Type Alias)
  type strOrNum = string | number;

  var sampleAlias: strOrNum;
  sampleAlias = 12345;
  console.log(sampleAlias);
  sampleAlias = "一二三四五";
  console.log(sampleAlias);

  type Text = string | { text: string };
  type Coordinates = [number, number];
  type Callback = (data: string) => void;

  var sampleText: Text;
  sampleText = "型エイリアス";
  console.log(sampleText);
  sampleText = { text: "型エイリアス" };
  console.log(sampleText);
  console.log(sampleText.text);

  var sampleCordinates: Coordinates;
  sampleCordinates = [0, 100];
  console.log(sampleCordinates);
  console.log(sampleCordinates[0]);
  console.log(sampleCordinates[1]);

  var sampleCallback: Callback;
  sampleCallback = (data: string) => console.log(data);
  sampleCallback(`
  ひ|日
  ふ|風
  み|水
  よ|世
  い|葦
  む|虫
  な|魚
  や|鳥
  こ|動物
  と|人間
  `);
} 

⇧ 全部の「型」は試せてないと思うけど、一旦、上記で保存。

■C:\Users\Toshinobu\Desktop\soft_work\typescript_work\src\main.ts

import * as lessonType from "./lesson_type";
import { ComExampleDemoType } from "../src/lesson_type";

ComExampleDemoType; 

後ほど、実行していきます。

VS CodeVisual Studio Code)で実行するには、「拡張機能」を追加する必要があるらしい…

なんか、「VS CodeVisual Studio Code)」で「TypeScript」を実行するには、tscコマンドで「JavaScript」ファイルにコンパイルしてから、「実行」するしかないのか分からないのだけど、

code.visualstudio.com

チュートリアルを見た感じ、コマンドでポチポチするしか無さそう...

Eclipseのような「統合開発環境IDE:Integrated Development Environment)」みたいにGUI上から実行できないらしいというね...

なんか、

qiita.com

qiita.com

⇧「拡張機能」を追加すればイケるらしい。

というわけで、追加してみる。

f:id:ts0818:20211229143307p:plain

「TypeScript」の場合は、「npm」の「モジュール」で「t-node」というものも必要らしい。

f:id:ts0818:20211229143703p:plain

f:id:ts0818:20211229144019p:plain

f:id:ts0818:20211229144538p:plain

⇧ インストールしましたが、例の如く「-g」オプション付けずにインストールしているので、「settings.json」に追加する設定が変わるようです。

github.com

My solution is:

 "code-runner.executorMap": {
    "typescript": "node -r ts-node/register",
    "javascript": "node"
  }

I think it's better than the solution @formulahendry provided. You don't need care about the path like this: ${whatever PATH}/node_modules/.bin/ts-node. Because the PATH often changes.

https://github.com/formulahendry/vscode-code-runner/issues/162

⇧ 上記のような感じになるらしい。

というわけで、「.vscode/settings.json」の最後に追記。

{
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
      },
      "eslint.format.enable": false,
      "editor.formatOnSave": true,
      "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "[json]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "[typescript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "editor.lineNumbers": "on",
      "editor.rulers": [80],
      "editor.wordWrap": "on",
      "eslint.packageManager": "yarn",
      "files.insertFinalNewline": true,
      "files.trimTrailingWhitespace": true,
      "npm.packageManager": "yarn",
      "typescript.enablePromptUseWorkspaceTsdk": true,
      "code-runner.executorMap": {
        "javascript": "node",
        "typescript": "node -r ts-node/register"
      }
}

⇧ 上記で保存。

実行したい「.ts」ファイルを開いた上で右クリックし、「Run Code」を選択。

f:id:ts0818:20211229155007p:plain

「出力」タブに実行結果が出力されていれば、「TypeScript」が実行されてるようです。

f:id:ts0818:20211229214002p:plain

何だろう、「VS CodeVisual Studio Code)」ってデフォルトでできることが少なくない?

そもそも、「拡張機能」を追加しないと、普通に実行できないってどうなのよ...

いや、コマンドでポチポチと実行することはできるけど、それだと「コマンドプロンプト」使うのと変わらんやんけ、っていう話になってくると思うし...

あんまり便利な気がしないのは気のせいなのだろうか...

毎回モヤモヤ感が半端ない...

ちなみに

zenn.dev

github.com

⇧「ts-node」以外にも「esbuild-register」って「モジュール」もあるらしいのだけど、「拡張機能」の「Code Runner」で使えるのか試せてないですが、「npm」で「esbuild-register」をインストールして、

    ...省略
      "code-runner.executorMap": {
        "typescript": "node --require esbuild-register"
      }
    ...省略      

みたいな「設定」にすれば動くんじゃないかな?という気がしたので、

f:id:ts0818:20211229165529p:plain

f:id:ts0818:20211229165639p:plain

⇧ インストールして、「settings.json」を修正。

{
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
      },
      "eslint.format.enable": false,
      "editor.formatOnSave": true,
      "[javascript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "[json]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "[typescript]": {
        "editor.defaultFormatter": "esbenp.prettier-vscode",
      },
      "editor.lineNumbers": "on",
      "editor.rulers": [80],
      "editor.wordWrap": "on",
      "eslint.packageManager": "yarn",
      "files.insertFinalNewline": true,
      "files.trimTrailingWhitespace": true,
      "npm.packageManager": "yarn",
      "typescript.enablePromptUseWorkspaceTsdk": true,
      "code-runner.executorMap": {
        "javascript": "node",
        "typescript": "node --require esbuild-register"
        //"typescript": "node -r ts-node/register"
      }
}

で、実行したところ、動きました。

f:id:ts0818:20211229214058p:plain

⇧ 実行時間は早くなってる模様。

今回はこのへんで。