Typescript(インポート/エクスポート)

はじめに

TypeScript における import と export の書き方は JavaScriptと概ね同じですが、拡張子の扱いやTypeScript 固有の挙動である型のコンテキストにおけるimport,exportなどいくつか違いがあるので、この記事に書き残します。(主に自分の備忘録として...)
javascriptにおけるimport/exportについては以前記事にしましたのでそちらも参考にして下さい!
ES6(モジュール) - 駆け足エンジニアの記録

インポート/エクスポートのための準備

モジュール化するためにはいくつか設定が必要です。(webpackを使用している場合、必要ない設定等あるかもしれません)

①htmlのscriptタグ
    <script type="module" src="index.js"></script>

scriptタグには本来javascriptファイルのみ記載しているところを、上記のようにtype="module"と追記する必要があります。

②tsconfigの設定

tsconfig内"module"初期状態では"module": "commonjs",となっていると思いますが、"module": "ES2015",と変更する必要があります。
ES2015以外(ES2016など)ではエラーが生じました。

③インポート時の拡張子

この記事を作るにあたって、他の記事を読んでみたところ殆どの記事でTypeScript ではインポートの際 に読み込むファイルの拡張子を省略できる。……というより、拡張子を書くとエラーになるという内容を目にしました。おそらく拡張子を書くとエラーが生じる場合というのはwebpackやgulpを利用している場合だと思われます。

ここではバンドルツールやライブラリを使用しない前提で以下のケースを考えます。
2つのファイル(index.ts,app.ts)があり、indexをインポート用appをエクスポート用のファイルとします。また簡単にobjという変数をインポート/エクスポートする例とします。

//app.ts
export const obj = { name: "max", age: 22 };

//index.ts
import { obj } from "./app.js";

console.log(obj);//{name: "max", age: 22}

ここでのポイントはtsではなく拡張子jsが必要ということです。appファイルをインポートするタイミングは既にjavascriptコンパイルされた後です。最終的にはjavascriptファイルがインポートされるということです。
なので拡張子はtsではなくjsと記載しないとエラーが発生します。

以上がtypescriptにおけるインポート/エクスポートのための準備となります。

typescriptにおけるインポート/エクスポート

型定義によるインポート/エクスポート

Typescriptによる型定義(インターフェースや型エイリアス)といったものも import と export の対象になります。

//app.ts(エクスポート)
interface Person {
  name: string;
  age: number;
}
type AddFn = (a: number, b: number) => number;

export { Person, AddFn };


//index.ts(インポート)
import { Person, AddFn } from "./app.js";

const user1: Person = {
  name: "max",
  age: 22,
};
console.log(user1);//{name: "max", age: 22}

const addFn: AddFn = (a, b) => {
  return a + b;
};
console.log(addFn(2, 3));//5
②コンビネーションにおけるインポート/エクスポート

先に例を提示します。以下BMIの値を求めるという例です。

//app.ts(エクスポート)
type Gender = "male" | "female";
interface Person {
  name: string;
  height: number;
  weight: number;
  gender: Gender;
}

const Person = {
  BMI: (person: Person): number => {
    const cmFromM = person.height / 100;
    const stWeight = cmFromM * cmFromM;
    return Math.floor(person.weight / stWeight);
  },
};

export { Person };

インターフェースとオブジェクトが、同じ Person という名前で定義されてます。TypeScript では、同じ名前空間の中に『変数宣言空間(Variable Declaration Space)』と『型宣言空間(Type Declaration Space)』という 2 つの宣言空間が存在してい て、名前の管理が別々になっています。そのためPersonのように変数や関数と型で同一の名前を持つことができます。型と同じ名前のオブジェクトを定義することを一般にコンビネーションと呼ばれます。

export { Person}によるエクスポートはインターフェースのPersonとオブジェクトのPersonどちらもエクスポートされます。

//index.ts(インポート)
import { Person } from "./app.js";

const user1: Person = {
  name: "hiroki",
  height: 179,
  weight: 71,
  gender: "male",
};
console.log(Person.BMI(user1));//22

このようにインターフェースの Person とオブジェクトの Personを一つのインポート文でどちらも使えるようになります。