krrkr-space

メモ・記録・共有

【Neovim】telescope-cocでジャンプ元をjumplistに追加する

Telescope coc definitionsで定義に飛んだ後に元の使用箇所に戻ろうとして<C-o>したら知らんとこにぶっ飛んでってしまうのでちゃんと元の場所に戻れるようにする。

Telescope coc definitions push_cursor_on_edit=true

自キーマップ

vim.keymap.set({ 'n' }, '<Leader>f', '[telescope]', { remap = true })
vim.keymap.set({ 'n' }, '[telescope]gd', '<Cmd>Telescope coc definitions push_cursor_on_edit=true<CR>')
-- 他にも[telescope]*でキーマップ色々が続く

参考: github.com

telescope-coc以外でも独自のpickerを提供するプラグインの場合同様にする必要があると思われる…というか上のPRを見ると組み込みpickerでもmarks・lsp_references・lsp_document_symbolsでしかデフォルトtrueでないのでその他のpickerもおそらくそう。

【TypeScript】グローバル変数の型定義を書く方法

出題

問題:以下の状態で型がHogeのグローバル変数gが存在することを示す型定義を書き足すにはどのようにすればいいでしょうか?

// sample.d.ts
declare class Hoge {
  a: number;
  sayA: () => void;
}

正解:

// sample.d.ts
declare class Hoge {
  a: number;
  sayA: () => void;
}

declare var g: Hoge; // こう

問題:ではHogeの定義が外部モジュールにあってimportする場合、つまり以下の場合に同様のグローバル変数gが存在することを示す型定義を書き足すにはどのようにすればいいでしょうか?

// sample.d.ts
import { Hoge } from 'hoge-module'

正解:

// sample.d.ts
import { Hoge } from 'hoge-module'

// こう
declare global {
  var g: Hoge;
}

まだ色々と慣れていないだけかもしれないけど、ちゃんとこれにたどり着くのに結構時間かかってしまった…

解説

前者と後者では同じ型定義ファイルでも前者はスクリプト、後者はモジュールとして扱われる。違いはtop-level importやexportがあるかどうか。

そしてスクリプト上のvarはグローバルスコープである一方、モジュール上のvarはモジュールスコープ。

www.typescriptlang.org

In TypeScript, just as in ECMAScript 2015, any file containing a top-level import or export is considered a module. Conversely, a file without any top-level import or export declarations is treated as a script whose contents are available in the global scope (and therefore to modules as well).

なので、スクリプトの方はdeclare varでグローバル変数となるけども、モジュールの方ではそのままではダメ。

モジュールでグローバル変数を型定義するには以下の通り。

www.typescriptlang.org

ややこしいかもしれないポイント

躓いたのはおそらく、型定義を書きたかっただけなのに型定義ファイルにもスクリプト/モジュールの区別が発生したから(そして発生することを知らなかったから)だと思う。

jsにコンパイルされるファイルであればもちろんjsと同様にスクリプト・モジュールの扱いがあるのはわかるのだけど、型定義だけ独立しているファイルにその区別が発生するのがなかなかしっくりこなかった…


どこかでそもそも型定義ファイルはあくまでtsjsのトランスパイル時にjsファイルと合わせて生成されることを想定しており型定義だけを独立して書いたり扱うのは当初の想定外という話を見た気がする(ソースが見つかれば貼る)
であれば型定義ファイルもトランスパイル元のts(そしてトランスパイルの結果のjs)がスクリプトならスクリプト、モジュールならモジュールという区別があるのは自然に思う。

※追記

import types(import(...)型)を使用して以下のようにしてもOK

sample.d.tsがモジュールではなくグローバルスコープのままになる点でこちらの方がよさそう

// sample.d.ts
declare var g: import('hoge-module').Hoge;

参考文献

import typesについて www.typescriptlang.orgimport type from ...と紛らわしく検索はほぼそちらの情報で埋まっているので出てきにくい) stackoverflow.com zenn.dev stackoverflow.com