TypeScript: 38の具体例から学ぶnamed export

本稿では、TypeScriptの`export`の書き方のうち、named exportに限定して、多数の具体例を用意しました。具体例を見ながら、`export`の使い方を学ぶという趣旨です。良く使う書き方、あまり使わない書き方、いろいろあります。

具体例を一般化しながら、抽象的な構文知識を得たい人向けです。抽象的な文法から入りたい人は、各公式ドキュメントをご参照ください:

* [export - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/export)
* [ECMAScript® 2020 Language Specification - 15.2.3 Exports](https://tc39.es/ecma262/#sec-exports)
* [Modules · TypeScript](https://www.typescriptlang.org/docs/handbook/modules.html)
* [TypeScript/spec.md at master · microsoft/TypeScript - 11.3.4 Export Declarations](https://github.com/microsoft/TypeScript/blob/master/doc/spec.md#11.3.4)

#### 変数のexport

変数の定義と同時に、変数をexportする:

```typescript:module.ts
export const value1 = 1
export let value2 = 2
export var value3 = 3

// インポート方法: import {value1, value2, value3} from './module'
```

変数の定義と、そのexportを分ける:

```typescript:module.ts
const value1 = 1
let value2 = 2
var value3 = 3
export {value1}
export {value2}
export {value3}

// インポート方法: import {value1, value2, value3} from './module'
```

1回のexportで3つの変数を一気にexportする:

```typescript:module.ts
const value1 = 1
let value2 = 2
var value3 = 3
export {value1, value2, value3} // エクスポートリストと呼ばれます

// インポート方法: import {value1, value2, value3} from './module'
```

複数の変数定義と、exportを同時する:

```typescript:module.ts
export const value1 = 1, value2 = 2, value3 = 3 

// インポート方法: import {value1, value2, value3} from './module'
```

別の変数名としてexportする:

```typescript:module.ts
const foo = 1
export {foo as value}

// インポート方法: import {value} from './module'
```

変数の情報だけをexportする:

```typescript:module.ts
const FOO = 'FOO'
export type {FOO}

// インポート方法: import {FOO} from './module'
// ただし、FOOの使用には、typeof演算子が必要です:
// const foo: typeof FOO = 'FOO'
```

変数の型だけをexportする:

```typescript:module.ts
const FOO = 'FOO'
export type FOO = typeof FOO

// インポート方法: import {FOO} from './module'
// この場合、typeof演算子は不要です:
// const foo: FOO = 'FOO'
```

#### 関数のexport

関数の定義とexportを同時にする:

```typescript:module.ts
export function func() {
}

// インポート方法: import {func} from './module'
```

関数の定義とexportを別々にする:

```typescript:module.ts
function func() {
}
export {func}

// インポート方法: import {func} from './module'
```

#### 匿名関数のexport

匿名関数はnamed exportできません:

```typescript:module.ts
export function () { // エラー
}
```

#### 配列のexport

配列のexportは、変数のexportと同じ:

```typescript:module.ts
export const array = [1, 2, 3]

// インポート方法: import {array} from './module'
```

`as const`をつけると、タプル型としてexportできます:

```typescript:module.ts
export const array = ['foo', true] as const
//=> このarrayは ['foo', true] 型になります

// インポート方法: import {array} from './module'
```

配列を分割代入しながらexportする:

```typescript:module.ts
const array = [1, 2, 3]
export const [val1, val2, val3] = array

// これは下記と同じ意味です
// export const val1 = array[0]
// export const val2 = array[1]
// export const val3 = array[2]

// インポート方法: import {val1, val2, val3} from './module'
```

配列を要素と余剰部分に分けながらexportする:

```typescript:module.ts
const array = [1, 2, 3]
export const [val1, ...rest] = array

// これは下記と同じ意味です
// export const val1 = array[0]
// export const rest = [array[1], array[2]]

// インポート方法: import {val1, rest} from './module'
```

#### オブジェクトのexport

オブジェクトリテラルは、変数のexportと同様です:

```typescript:module.ts
export const obj = {FOO: 1, bar: 2}

// インポート方法: import {obj} from './module'
```

この場合、`obj`の型は、`{FOO: number, bar: number}`になります。型の制約を追加しつつexportすることもできます:

```typescript:module.ts
export const obj = {FOO: 1 as const, bar: 2}
//=> {FOO: 1, bar: number} 型としてexportされる

export const obj = {FOO: 1, bar: 2} as const
//=> {FOO: readonly 1, bar: readonly 2} 型としてexportされる

// インポート方法: import {obj} from './module'
```

オブジェクトを分割代入しながらexportする:

```typescript:module.ts
const obj = {foo: 1, bar: 2}
export const {foo, bar} = obj

// これは下記と同じ意味です
// export const foo = obj.foo
// export const bar = obj.bar

// インポート方法: import {foo, bar} from './module'
```

オブジェクトを分割代入+名前変更しながらexportする:

```typescript:module.ts
const obj = {foo: 1, bar: 2}
export const {foo: hoge, bar: piyo} = obj

// これは下記と同じ意味です
// export const hoge = obj.foo
// export const piyo = obj.bar

// インポート方法: import {hoge, piyo} from './module'
```

オブジェクトを分割代入+余剰パターンに分けながらexportする:

```typescript:module.ts
const obj = {foo: 1, bar: 2, buz: 3}
export const {foo, ...barAndBuz} = obj

// これは下記と同じ意味です
// export const foo = obj.foo
// export const barAndBuz = {bar: obj.bar, buz: obj.buz}

// インポート方法: import {foo, barAndBuz} from './module'
```


#### クラスのexport

クラスの定義とexportを同時する:

```typescript:module.ts
export class Class {}

// インポート方法: import {Class} from './module'
```

クラス定義とexportを別々にする:

```typescript:module.ts
class Class {}
export {Class}

// インポート方法: import {Class} from './module'
```

クラスの型だけをexportする:

```typescript:module.ts
class Class {}
export type {Class}

// インポート方法: import {Class} from './module'
// インポート側は new Class はできませんが、型としてClassを参照することができます。
```

#### 匿名クラスのexport

匿名クラスは変数としてexportします:

```typescript:module.ts
export const AnonymousClass = class {}

// インポート方法: import {AnonymousClass} from './module'
```

#### インスタンスのexport

インスタンスは変数としてexportします:

```typescript:module.ts
export const instance = new Class()

// インポート方法: import {instance} from './module'
```

#### 匿名クラスのインスタンスのexport

匿名クラスのインスタンスのexportは変数と同じやりかたです:

```typescript:module.ts
export const instance = new class {}

// インポート方法: import {instance} from './module'
```

#### インターフェイスのexport

インターフェイス定義とexportを同時にする:

```typescript:module.ts
export interface Interface {
}

// インポート方法: import {Interface} from './module'
```

インターフェイス定義とexportを別々にする:

```typescript:module.ts
interface Interface {
}
export {Interface}

// インポート方法: import {Interface} from './module'
```

インターフェイスを別名でexportする:

```typescript:module.ts
interface Interface {
}
export {Interface as FooInterface}

// インポート方法: import {FooInterface} from './module'
```

#### 型エイリアスのexport

型エイリアスの定義とexportを同時にする:

```typescript:module.ts
export type Status = 'OK' | 'NG'

// インポート方法: import {Status} from './module'
```

型エイリアスの定義と、exportを別々にする:

```typescript:module.ts
type Status = 'OK' | 'NG'
export {Status}

// インポート方法: import {Status} from './module'
```

型エイリアスを別名でexportする:

```typescript:module.ts
type Status = 'OK' | 'NG'
export {Status as FooStatus}

// インポート方法: import {FooStatus} from './module'
```

#### 名前空間のexport

名前空間を定義しつつ、exportする:

```typescript:module.ts
export namespace FooSpace {
  export const value = 1
}

// インポート方法: import {FooSpace} from './module'
```

名前空間の定義とexportを別々に行う:

```typescript:module.ts
namespace FooSpace {
  export const value = 1
}
export {FooSpace}
// インポート方法: import {FooSpace} from './module'
```

#### re-export (再エクスポート)

すべてをimportしつつ、すべてをexportする:

```typescript
// module.ts
export const value = 1
export function func() {}
export class Class {}

// re-rexport.ts
export * from './module'

// インポート方法
import {value, func, Class} from './re-rexport'
```

特定のものだけre-exportする:

```typescript
// module.ts
export const value = 1
export function func() {}
export class Class {}

// re-rexport.ts
export {value, func} from './module' // Classを除外している
// これは下記と同じ意味
// import {value, func} from './module'
// export {value, func}

// インポート方法
import {value, func} from './re-rexport'
```

別名でre-exportする:

```typescript
// module.ts
export const value = 1
export function func() {}
export class Class {}

// re-rexport.ts
export {value as foo, Class as FooClass} from './module'
// これは下記と同じ意味
// import {value, func} from './module'
// export {value as foo, Class as FooClass}

// インポート方法
import {foo, FooClass} from './re-rexport'
```

importしたすべてを、ひとつのオブジェクトに束ねてre-exportする:

```typescript
// module.ts
export const value = 1
export function func() {}
export class Class {}

// re-rexport.ts
export * as module from './module'

// インポート方法
import {module} from './re-rexport'
console.log(module.value)
console.log(new module.Class())
console.log(module.func())
```

特定のものだけを、ひとつのオブジェクトに束ねてre-exportする:

```typescript
// module.ts
export const value = 1
export function func() {}
export class Class {}

// re-export.ts
import {value, func} from './module'
export const module = {value, func} // Classを除外している

// インポート方法
import {module} from './re-rexport'
console.log(module.value)
console.log(module.func())
```

---

最後までお読みくださりありがとうございました。Twitterでは、Qiitaに書かない技術ネタなどもツイートしているので、よかったらフォローお願いします:relieved:→[Twitter@suin](https://twitter.com/suin)