19
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

シーエー・アドバンスAdvent Calendar 2020

Day 2

Typescript で 型の import 文を減らす方法・滅す方法

Last updated at Posted at 2020-12-01

型importとは

Typescriptで、型情報を使用するためにimport/fromしている箇所をそう呼んでいます:santa:

User.ts

export interface User{
 name: string;
 age: number;
}
sample.ts
import { User } from "./User" // 型import

const user = http<User>(url, option)

いまはひとつだけだからいいのですが、型安全にしていくと
レスポンスをするための型importや、マテリアルデザインの型情報、などimportが積もっていきます。
型のimport自体は、Typescriptでしか必要ありません。

結論

  1. interface をまとめた ファイル を用意(減らす)
  2. declare global 宣言を使用(滅す)

「減らす」と「滅す」は漢字似てるけど大違い:santa:

背景

例えば、webpack.config.jsをTypescriptで書こうとすると、下記の型import量になります(sassやfiber入れるともっと増えます)

webpack.config.ts
import { join, resolve } from 'path';
import { env } from 'process';
import { Configuration, HotModuleReplacementPlugin, ProvidePlugin } from 'webpack'; // 3分の1型
import { Configuration as DevServerConfig } from 'webpack-dev-server'; // 型
type NODE_ENV = 'development' | 'production' | 'none'; // 型

const { NODE_ENV } = env;

const config: Configuration & DevServerConfig = {
  mode: NODE_ENV as NODE_ENV,

  ~~ 省略 ~~

ReactでMaterial-UIとか使うと、ファイルのファーストプレビューのほぼimport文やで!!!

interface や、class、返却値の型アサーションなど、「型のための import 文」を減らしたい。
型importはまた別のところでのさばってしまう!

動機

「型の import」って、「読む」ときは都合よく非表示ならんかな(ならない)
省略していいのでは(いや、省略できるはずだ)
書くのは1回で終わりたい!

お館さまに聞いてみよう

型 import のことは私が容認していた。みんなにも認めてもらいたいと思っている。

しかし・・・

コードはコードです。
長くて、読むに値しないコードはすべて省略対象かと!

鬼の対義語があるとしたら、それはお館さま

そうだね。ただ・・・やるとしたら

ファイルモジュールを使うことを強くお勧めします。

御意orz(否定せず道を指し示してくれる姿勢涙)

参照:globals.d.ts

【考えその1】お館様の望むままに従います

→ interface の呼吸・型のわななき

ファイルモジュールの方式

【考えその2】心より尊敬するお館さまであるが、理解できない考えだ。全力で反対する!

→ 「declare global の呼吸・型輸入全焼却滅」

型のimportは不要になります。

自分は「型輸入全焼却滅」をしましたが、お館さまは型の ファイルモジュールの方式 を推奨をしているようです。

ようやく詳細

interface の呼吸・型のわななき

ファイルモジュールにサンプルがないのですが、きっとimport/exportを用いた方法のことでしょう。
そして、型をexportするにはいろいろ方法があり、type aliasも手ですが、ここではinterfaceを用います。
interfaceはtype aliasもねじれ渦🌀のように巻き込めます

やること

  1. definition.ts(ファイル名はなんでもよいです)を用意
  2. definition.tsにinterfaceを記述して、key/valueを用意
  3. import先でkeyを指定する(例:WebpackConfig['config']
definition.ts
import { Configuration } from 'webpack';
import { Configuration as DevServerConfig } from 'webpack-dev-server';
type NODE_ENV = 'development' | 'production' | 'none';

export interface WebpackConfig {
  config: Configuration;
  devServerConfig: DevServerConfig;
  NODE_ENV: NODE_ENV;
}
webpack.config.ts
import { join, resolve } from 'path';
import { env } from 'process';
import { HotModuleReplacementPlugin, ProvidePlugin } from 'webpack';
import { WebpackConfig } from './definition'; // 追加

const { NODE_ENV } = env;

const config: WebpackConfig['config'] & WebpackConfig['devServerConfig'] = { // 変更
  mode: NODE_ENV as WebpackConfig['NODE_ENV'], // 変更

  ~~ 省略 ~~

ひとつのimport文で必要なkey名を指定するパターンですね!
いろんなライブラリーがとっている手段ですね!

ただ、configに当てた型を見てください!

webpack.config.ts
const config: WebpackConfig['config'] & WebpackConfig['devServerConfig'] = { // 変更

型が冗長になりがちですね!
これはなんという型だ!?

Static types for dynamically named propertiesという異国の名だと!
長い!

declare global の呼吸・型輸入全焼却滅

やること

  1. definition.ts(ファイル名はなんでもよい!馬の骨でもいい!)を用意する
  2. declare globalを用意して、key/valueをつくる
definition.ts
import { Configuration } from 'webpack'; // 型
import { Configuration as DevServerConfig } from 'webpack-dev-server'; // 型
type NODE_ENV = 'development' | 'production' | 'none'; // 型

declare global {
  type webpackConfig = Configuration;
  type devServerConfig = DevServerConfig;
  type nodeEnv = NODE_ENV;
}
webpack.config.ts
import { join, resolve } from 'path';
import { env } from 'process';
import { HotModuleReplacementPlugin, ProvidePlugin } from 'webpack';

const { NODE_ENV } = env;

const config: webpackConfig & devServerConfig = { // 変更
  mode: NODE_ENV as nodeEnv, // 変更

ほとんど、interface の呼吸・型のわななきとやっていることはほぼ変わらない!?
ですが、configの型をみてください

webpack.config.ts
const config: webpackConfig & devServerConfig = { // 変更

重複した箇所も消えて、とても読みやすくなってます!おまけにwebpack.config.tsから型のimport文を滅すことができました!

しかし、よく調教されたJS・TS使いはglobalという言葉にとても敏感じゃ。
本当の本当にglobalを使っていいんですか?

もし型の名称の衝突が起こった時は、鎹鴉(VSCode)が知らせてくれるので大丈夫だと思います。

というか、Typescriptは鎹鴉(VSCode)頼みです。

たとえ、VSCodeがFinalCutPro並みの金額だろうと買うと思います(経費で)

まとめ

  • 型のimport文を減らすには、ファイルモジュールを使う(型のわななきの方)←TypeScript Deep Dive 推奨
  • 型のimport文を滅すには、global declareを使用(型輸入全焼却滅の方)

おわりに

あぁー鬼滅要素いれて、ややこしくしてしまった気が:santa:

参照

19
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?