Skip to content

Instantly share code, notes, and snippets.

@tk0miya
Last active April 21, 2024 09:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tk0miya/572cad81356b76868865d75b0ea80160 to your computer and use it in GitHub Desktop.
Save tk0miya/572cad81356b76868865d75b0ea80160 to your computer and use it in GitHub Desktop.
# included ブロックの型エラーを解消する

included ブロックの型エラーを解消する

ひとつ前の記事では Steep に追加予定の ignore コメント機能を紹介しました。

その記事の中で、ActiveSupport::Concern で提供されている included ブロックのことを 解消の難しい型エラー と紹介しましたが、 ブログ記事にまとめていく最中に解決方法を思いつきました。

問題の整理

そもそもどういう問題だったのかを改めて整理します。

手元のコードでは、concern 系クラスの included ブロックで型エラーが起きていたという話です。 included ブロック内では、 include 先のクラスとして コードが実行されるのですが、Steep はこのブロック内で self が切り替わっていることが判別つかず、 Concern クラスとして判定を進めようとするため、型エラーが発生します。

module Loginable
  extend ActiveSupport::Concern

  included do
    helper_method :foo  #=> Type `singleton(::Loginable)` does not have method `helper_method`
  end
end

上記の例では singleton(::Loginable) にメソッドがないと言っていますよね。

前回の記事では、この問題は解消が難しいので、ignore コメントで型エラーを黙らせることにしました。

解決方法

上の「問題の整理」のところに書いたことにヒントがあります。 「include 先のクラスとして」コードが実行される、「このブロック内で self が切り替わっている」という部分です。 つまり、include 先のクラスの情報を Steep にヒントとして与えてあげれば、型エラーが解消するというわけです。

実際には、次のようなアノテーションコメントを書きます。

module Loginable
  extend ActiveSupport::Concern

  included do
    # @type self: singleton(ActionController::Base)
    helper_method :foo
  end
end

このコメントを書くことで、Steep に対して「このブロック内では self を ActionController::Base クラスとして扱うように」と伝えることができます。

アノテーションコメント

Steep には、このように型情報を補足するためのアノテーションコメントが用意されています。 RBS では表現できない、ブロック単位での型情報や変数の型情報などを Ruby のコメントとして記述できます。

Ruby では DSL や宣言的な記述が好まれ、コンテキストの切り替わるブロックがそこかしこにありますが、 現状では RBS だけでこうしたブロック表現をカバーし切るのは難しいため、アノテーションコメントを併用するのがよさそうです。

また、メソッド内、ブロック内の変数の型情報などを補うのも有用です。 前回の記事で #present? による型の絞り込みができないという話をしましたが、これもアノテーションコメントを使うことで解消できます。

num = [1, 2, 3, nil].sample  #=> Integer?
if num.present?
  # @type var num: Integer
  num.succ  #=> #present? では型が絞り込まないが、アノテーションコメントによって Integer と扱われるため、型エラーは発生しない
end

理想としてはツール側の進化で改善してほしいところですが、adhoc な対応として、アノテーションコメントを使って回避する手もあります。 アノテーションコメントを多用するとコードが読みづらくなりますし、どこを ignore して、どこにアノテーションをするとよいのか、というバランスが難しいところですが、 型エラーを解消する手段のひとつとして覚えておくとよいでしょう。

まとめ

  • アノテーションコメントの紹介
  • アノテーションコメントを使うと included ブロックの型エラーが解消できること
  • 容量用法を守って正しくお使いください
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment