🍴

Typescript、VSCodeのMove to new file は便利だぞという話

2021/10/19に公開

Move to a new file を使おう

VSCodeのリファクタリング機能はとても便利ですが、とりわけMove to a new fileは使い方を覚えると、コーディング作業の速度をかなり上げることができます。

「1つのファイルに関数を詰め込みすぎない、理想を言うなら1つの関数に1つのファイル。しかし、importの整理や、ファイルの作成の手間を考えると、ちょっと億劫……。」という人も少なく無いと思います。
そんな時は、纏めて書いた後にMove to a new fileで切り出していく手法を覚えておくととても便利です。

例えばこんなシチュエーション

foo.tsfoo()を書いていた。ファイル内で作っていたbar()は別のファイルに分けたくなった

// foo.ts
import { baz } from './baz';

export function foo() {
  return bar();
}
// ここから下を選択し、リファクタリング -> Move to a new file
function bar() {
  return baz();
}

こんな時にMove to a new fileを使いましょう。自動的にbar.tsを生成し、importの整理も自動で行います。コピペで行うと、ファイルの作成と命名、importの整理といった面倒な手作業が多く発生します。

// foo.ts
import { bar } from './bar';

export function foo() {
  return bar();
}
// bar.ts
import { baz } from './baz';

export function bar() {
  return baz();
}

応用

Move to a new fileで切り出したときのファイル名は、選択範囲の一番上の変数 or 関数の名前になります。範囲内に変数や関数の候補がない場合はnewFileになります。

その1 好きなファイル名で出力する

ファイル名にしたい変数を一時的に定義した後、Move to a new fileを任意のファイル名(変数や関数名で使える範囲に限る)で出力することができます。index.tsなどにリネームしたい場合に少し楽ができます。

// ここから下を選択し、Move to a new fileすると index.ts が生成される
const index = 0;

function bar() {
  return baz();
}

応用その2 ファイルと関数、両方のリネーム

bar()を切り出してbar.tsで作ったけれど……。やっぱりhoge()にしたかったなぁ」なんてこともあると思います。
ファイル名も合わせてhoge.tsにリネームしてしまいたいところです。その場合、シンボルの名前変更で関数の名前をリネームした後、もう一度Move to a new fileをすると良いです。

// bar.ts
import { baz } from './baz';

// barを選択し、シンボルの名前を変更でhogeに変更
// barをimportしている関数も自動でリネームされる
function bar() {
  return baz();
}

// bar.ts
import { baz } from './baz';

// ここから下を選択し、Move to a new fileすると
// hoge.tsが生成され、中身がなくなったbar.tsは空ファイルになる
function hoge() {
  return baz();
}

この操作により、新たにhoge.tsが生成され、bar.tsの中身は空になります。空になったbar.tsを消してあげると、実質リネームが完了します。

その3 単体テストを書く手間を少し節約

例えばJest等で、foo.tsに対応するテストをfoo.test.tsfoo.spec.tsとして、同じフォルダに格納している場合、テストコードを関数の下にいきなり書くことで、importを書く手間を少し省けます。

// foo.ts
export function foo() {
  return 1;
}

// fooの真下にfooのテストコードを書き、Move to a new fileする
describe(foo, () => {
  it('1を返す', () => {
    expect(foo()).toBe(1);
  });
});

describe以降の行を選択してMove to a new fileすると、同じフォルダにnewFile.tsが生成されます。

// newFile.ts
import { foo } from './foo.ts'

describe(foo, () => {
  it('1を返す', () => {
    expect(foo()).toBe(1);
  });
});

newFile.tsをテスト用のファイル名のfoo.test.tsにリネームしてあげると、必要なimportを備えた単体テストファイルが出来上がります。

更におすすめの設定とか

importやファイル名の管理は、地味に時間を費やす作業のため、可能な限りIDEの支援を活用するのが理想的だと思います。Workspaceの.vscode/setting.jsonに、eslintやstylelint、prettierやimport整理を自動で行う設定を追加しておくと、気持ちよく切り出すことができるのでオススメです

{
  "editor.codeActionsOnSave": [
    "source.organizeImports",
    "source.addMissingImports",
    "source.removeUnusedImports",
    "source.fixAll.eslint",
    "source.fixAll.stylelint",
  ],
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "editor.formatOnType": true,
  "typescript.preferences.importModuleSpecifierEnding": "minimal",
  "javascript.preferences.importModuleSpecifierEnding": "minimal"
}

Discussion