RBSのuntyped, void, top, botの違いを理解する #asakusa_bashi_rbs
RBSのdocs/syntax.mdに記載されている untyped, void, top, bot の違いを理解したけど、また忘れそうなのでブログにまとめておく。
untyped
どんな型でも代入できて、その変数を型検査の対象にしない場合に使う。
# ruby class User def greet(user) user.something end end # rbs class User def greet: (untyped) -> void end
something
メソッドの定義は存在しないのに、Steepの型検査でエラーは出ない。
No type error detected. 🫖
void
メソッドの戻り値を使わない場合に使う。
# ruby class User def foo bar.upcase end def bar "hello" end end # rbs class User def foo: () -> String def bar: () -> void end
void である戻り値に対して upcase
のメソッドを呼び出しているため、Steep の型検査でエラーが出る。
app/user.rb:3:8: [error] Type `void` does not have method `upcase` │ Diagnostic ID: Ruby::NoMethod │ └ bar.upcase ~~~~~~
top
どんな型でも代入できるが、その変数でメソッド呼び出しを禁止したい場合に使う。TypeScriptのunknown型と同じ。
# ruby class User def greet(user) puts user.name end end user = User.new user.greet("Pikachu") user.greet(1) # rbs class User def greet: (top) -> void end
型検査で引数に String と Integer を渡している部分ではエラーになっていないが、name
のメソッドを呼ぶところはエラーが出る。
app/user.rb:3:14: [error] Type `top` does not have method `name` │ Diagnostic ID: Ruby::NoMethod │ └ puts user.name ~~~~
bot
例外が必ず発生するか、無限ループで終了しないメソッドで使う。TypeScriptのnever型と同じ。
# ruby class User def foo raise NotImplementedError end def bar loop do puts "hello" sleep 1 end end def buz puts "hi, Eevee" end end # rbs class User def foo: () -> bot def bar: () -> bot def buz: () -> bot end
Steepで型検査すると foo, bar は問題ないが、 buz は実装が誤っているためエラーが出る。
app/user.rb:13:6: [error] Cannot allow method body have type `nil` because declared as type `bot` │ nil <: bot │ │ Diagnostic ID: Ruby::MethodBodyTypeMismatch │ └ def buz ~~~