TypeScript v2 playground plugin

TSCompilerAPI座談会
Leko

Leko

4月からシンガポールに住みます

Innovator

— gqlquramy { name } on Twitter: "#typescript My first playground plugin works :) https://t.co/8OHq0i07BX" / Twitter

Context

  • TypeScript v2 docs is under development (suffix: /v2/)
  • New playground has plugin system 🙄
  • It can load local plugin through localhost 🤯

Getting started

Tutorial: Link

yarn create typescript-playground-plugin xxx
cd xxx
yarn start

作った

— Leko/ts-playground-plugin-stackoverflow

使えるよ

やってること

  • コードが変更されたら型チェックを実施
  • エラーメッセージをStackExchange APIで検索
  • 整形、出力

型チェック

— gqlquramy { name } on Twitter: "@L_e_k_o https://t.co/jMlDJJUhxM" / Twitter

型チェック(コード)

// ...
modelChangedDebounce(sandbox, model) {
  sandbox.getWorkerProcess().then((worker) =>
    Promise.all([
      worker.getSemanticDiagnostics(model.uri.toString()),
      worker.getSyntacticDiagnostics(model.uri.toString()),
    ])
  )
    .then(([semanticDiagnostics, syntacticDiagnostics]) =>
      semanticDiagnostics.concat(syntacticDiagnostics)
    )
    .then(diagnostics => {
      // ハンドリングする
    })
  // ...
}

StackOverflowで類似検索

本筋じゃないのでAPIドキュメントと私のコード参照

型エラー

1: const port = process.env.PORT;
                ^^^^^^^
error TS2580: Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i @types/node`.

こういうの

エラーの整形

1: const port = process.env.PORT;
                ^^^^^^^

↑Diagnosticsのstart, lengthからオレオレ生成

error TS2580: Cannot find name 'process'. Do you need to install type definitions for node? Try `npm i @types/node`.

↑Compiler APIの一部を使用

Diagnostic

    export interface DiagnosticRelatedInformation {
        category: DiagnosticCategory;
        code: number;
        file: SourceFile | undefined;
        start: number | undefined;
        length: number | undefined;
        messageText: string | DiagnosticMessageChain;
    }
    export interface Diagnostic extends DiagnosticRelatedInformation {
        /** ... */
        reportsUnnecessary?: {};
        source?: string;
        relatedInformation?: DiagnosticRelatedInformation[];
    }

messageTextといいつつstringではない

        messageText: string | DiagnosticMessageChain;

ts.formatDiagnositc

import type { FormatDiagnosticsHost } from 'typescript'

const formatDiagnosticHost: FormatDiagnosticsHost = { /* ... */ }
const errorMessage = ts.formatDiagnostic(d, formatDiagnosticHost)

FormatDiagnosticsHost

declare namespace ts {
    // ...
    export interface FormatDiagnosticsHost {
        getCurrentDirectory(): string;
        getCanonicalFileName(fileName: string): string;
        getNewLine(): string;
    }

雑な実装例

const formatDiagnosticHost: FormatDiagnosticsHost = {
  getCurrentDirectory() {
    return ''
  },
  getCanonicalFileName(fileName: string) {
    return fileName
  },
  getNewLine() {
    return '\n'
  }
}

Your toys, our sandbox

https://www.typescriptlang.org/v2/dev/playground-plugins/

終わり