Panda Noir

JavaScript の限界を究めるブログでした。最近はいろんな分野を幅広めに書いてます。

access(obj, 'foo.bar.baz') みたいにパスを指定してアクセスしたい

発端: ApolloClient の useQuery の data と error をいい感じに扱うために getOrThrow(data, error, 'path.to.field') みたいなユーティリティ関数が欲しくなった

欲しい関数

const {loading, error, data} = useQuery(query);
const fooBar = getOrThrow(data, error, 'foo.bar');
const fooBarBaz = getOrThrow(data, error, 'foo.bar.baz');

こんな感じで、foo.bar でエラーが起きてたらエラーが throw され、エラーがなければ data.foo.bar が返ってくるという関数です。

実装:

さっそく実装を載せます(throw までつけると長くなるので、get に特化した実装を載せてます)。

ちなみに type-challenges の Object Key Paths の解答コードを借りました (こちらの解答)。

// cf. https://github.com/type-challenges/type-challenges/issues/7939
type ObjectKeyPaths<
  T extends object,
  P extends string = '', // prefix
  K extends keyof T = keyof T,
> =
  K extends string ?
    | `${P}${K}`
    | (T[K] extends object ? `${P}${K}${ObjectKeyPaths<T[K], '.'>}` : never)
  : never;

type Access<T extends object, U> =
  U extends `${infer x extends keyof T & string}.${infer xs}` ?
    T[x] extends object ?
      Access<T[x], xs>
    : T[x]
  : U extends keyof T ? T[U]
  : never;

const access = <T extends object, U extends ObjectKeyPaths<T>>(
  object: T,
  path: U,
): Access<T, U> =>
  path.split('.').reduce((acc, name) => (acc as any)[name], object) as any;

TypeScript: TS Playground - An online editor for exploring TypeScript and JavaScript

型を無理くりつけてるため実装に any を使ってます。これはもう仕方ないので、テストで保証すれば OK って方針にしました。

コマンドラインの内容を vim で編集できるようにする

zsh で control-o を押すと vim が立ち上がってコマンドラインの内容を編集できる関数を(ChatGPTが)作ったので紹介します。

(要件を伝えたら ChatGPT が目当てのものを一発で生成したので、かなりビックリしました。すごい。)

デモ動画

youtu.be

デモ動画では、コマンドラインの「vim ~/.config/zsh/.zprofile.local」の .zprofile.local を .zshrc.local に変えています。僕は vimmer なので、emacs キーバインドを使うより格段に早く修正できています。

実際のスクリプト

実際のスクリプトがこちら↓

# コマンドラインをエディタで編集する関数
edit-command-line() {
  # 現在のコマンドラインを一時ファイルに書き出す
  local tmpfile=$(mktemp)
  print -rl -- $BUFFER > $tmpfile

  $EDITOR $tmpfile < /dev/tty

  # エディタが正常に終了した場合、一時ファイルの内容でコマンドラインを置き換え
  if [[ $? -eq 0 ]]; then
    BUFFER=$(<$tmpfile)
    zle reset-prompt
  fi

  rm -f $tmpfile
}

zle -N edit-command-line
bindkey "^O" edit-command-line
  1. control-O を押す
  2. エディタが立ち上がる
  3. 編集して保存する
  4. エディタを終了する
  5. 編集内容がコマンドラインに反映される

なお、エディタを正常に終了しないと変更内容は破棄されます。たとえば vim なら :cq で終了するとコマンドラインは変更されません。

これ、zsh の vim モードで良いのでは?とも思うんですが、zsh の vim モードは絶妙に使いづらいんですよね… デフォルトがインサートモードである、プラグインが使えないあたりが個人的に致命的でした。

zellij のなかで neovim を開くと色がおかしくなる

結構試行錯誤したのでメモ

↑こんな感じで、結構色が違って表示されたので調べて修正しました。

結論

なぜか neovim の background オプションが "light" になってたのが原因でした。 set background=dark を明示的に書いたら解決しました。

調べたこと

  1. zellij を起動してない状態と起動した状態で比較してみる → zellij のなかでのみ問題が起きる 1.別のターミナルで zellij を起動してチェックしてみる → ターミナルを変えても同じ
  2. TrueColor は動くか? → zellij のなかでも問題なし
  3. system color は同じか? → 同じ
  4. bat など他コマンドの出力はどうか? → 問題ない

と、このように順番に原因を絞りました (zellijの起動に原因がありそう → 特定のターミナルと zellij の相性が原因ではなさそう → 色がおかしいわけではない → zellij が neovim になにか影響をしていてそれが原因っぽい)

ここからさらに neovim をプラグインなしで開いてもダメなことがわかったのでneovim 自体になにかあるんだと判明 → 最終的に background オプションに原因があることがわかりました。

幾野直人 (ikuno naoto) 自己紹介

諸事情(実名で検索すると他人の顔写真しか出てこない)のため、自己紹介記事を書くことにしました。目的を達成したら消したい。

プロフィール

  • 名前: 幾野直人(ikuno naoto)
  • 身長: 178cm (2024年4月現在)
  • 体重: 72.4kg (2024年4月現在)
  • BMI: 22.85
  • 得意な言語: TypeScript
  • 得意な技術: React

東北大学の工学部 電気情報物理工学科 情報工学コース 学士です(CS卒)。2024年4月から社会人5年目としてLINEヤフーで働いてます。

趣味の話

(プログラミングは言わずもがななので他の趣味の話)

  • 映画鑑賞
  • 合気道
  • ルービックキューブ
  • 料理
  • ギター

上のほうが熱が入ってる趣味です。合気道以外はコロナ禍に入ってから始めました。

映画は年200本くらい見ます。好きな映画は『ノッキン・オン・ヘブンズ・ドア』『四月の永い夢』『ロッキー3』『レオン』『ライフ・イズ・ビューティフル』『Love Letter』など。

合気道は大学から始めて9年目で二段です。

ほかの趣味はまあやってますって感じでそこまで熱がガッツリ入ってる感じじゃないので割愛。

vim でテキストオブジェクトを追加して [] を簡単に扱いたい

(){}dabyiB みたいに b/B で操作できますが、 []da[ と打たないといけません。煩わしいのでエイリアスを設定したいですよね。

というわけで r で [] を選択するテキストオブジェクトを追加しましょう!やり方がこちら↓

  1. vim-textobj-user をインストールする
  2. textobj#user#plugin を使って定義する
require 'lazy'.setup {
  {
    'kana/vim-textobj-user',
    event = 'VimEnter',
    config = function()
      vim.call('textobj#user#plugin', 'braces', {
        angle = {
          pattern = { "\\[", "\\]" },
          ["select-a"] = 'ar',
          ["select-i"] = 'ir',
        },
      })
    end
  },
}

これで、yardir[] を操作できます。