Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Type-only Migrate by AST

Takepepe
March 23, 2020

Type-only Migrate by AST

Takepepe

March 23, 2020
Tweet

More Decks by Takepepe

Other Decks in Technology

Transcript

  1. TypeScript Compiler API を使うことで、 TypeScript AST を簡単に取り扱う事が出来ます。 SourceFile ImportDeclaration ImportClause

    NamedImports ImportSpecifier Identifier ImportSpecifier Identifier ImportSpecifier Identifier StringLiteral EndOfFileToken import { A, B, C } from 'module'
  2. import 宣言は、ts.ImportDeclaration で表され… SourceFile ImportDeclaration ImportClause NamedImports ImportSpecifier Identifier ImportSpecifier

    Identifier ImportSpecifier Identifier StringLiteral EndOfFileToken import { A, B, C } from 'module'
  3. import 句は、ts.ImportClause で表され… SourceFile ImportDeclaration ImportClause NamedImports ImportSpecifier Identifier ImportSpecifier

    Identifier ImportSpecifier Identifier StringLiteral EndOfFileToken import { A, B, C } from 'module'
  4. すべての Node は、ts.Node のサブセットです。 SourceFile ImportDeclaration ImportClause NamedImports ImportSpecifier Identifier

    ImportSpecifier Identifier ImportSpecifier Identifier StringLiteral EndOfFileToken import { A, B, C } from 'module'
  5. SourceFile ImportDeclaration ImportClause NamedImports ImportSpecifier Identifier StringLiteral ImportDeclaration ImportClause NamedImports

    ImportSpecifier Identifier StringLiteral EndOfFileToken 元のSRCコードから、新しいSRCコードを得ることができます。 import { A } from 'module' import { B } from 'module'
  6. SourceFile ImportDeclaration ImportClause NamedImports ImportSpecifier Identifier StringLiteral ImportDeclaration ImportClause NamedImports

    ImportSpecifier Identifier StringLiteral EndOfFileToken それは、Node.js で JSON を組み替える作業と似ています。 import { A } from 'module' import { B } from 'module'
  7. SourceFile ImportDeclaration ImportClause NamedImports ImportSpecifier Identifier StringLiteral ImportDeclaration ImportClause NamedImports

    ImportSpecifier Identifier StringLiteral EndOfFileToken 型定義・ランタイム実装を「仕分け」し、"Type-only" import に変換します。 import { A } from 'module' import type { B } from 'module'
  8. const symbol = checker.getSymbolAtLocation(node) const aliasedSymbol = checker.getAliasedSymbol(symbol) checker.getSymbolAtLocation を用いて、

    単ファイルスコープの参照元となる ts.Symbol を取得。 これだけでは、import した定義の内訳を確認することができません。
  9. aliasedSymbol.flags === ts.SymbolFlags.Interface || aliasedSymbol.flags === ts.SymbolFlags.TypeAlias 最後に ts.SymbolFlags で定められた

    enum 値と評価し判別。 CompilerAPI には、この様に判別する enum がいくつか定義されています。
  10. 出力結果のソート制御は現状いれていませんが、 この辺りの設定も出来ると、コードの掃除にも使えそうです。 import { Const } from './a'; import {

    Let } from './b'; import type { TypeAlias, TypeAlias as TYPEALIAS } from './a'; import type { Interface, Interface as INTERFACE } from './b';
  11. コードジェネレーター・型を利用したチェッカーなど、 Compiler API なら可能なアイディアはまだまだあります。 ぜひ遊んでみてください。 import { Const } from

    './a'; import { Let } from './b'; import type { TypeAlias, TypeAlias as TYPEALIAS } from './a'; import type { Interface, Interface as INTERFACE } from './b';