Rubyの型解析ライブラリSorbetがリリースされたとの事でDocを参考に導入に挑戦!
進めていく内にrbファイルに# typed: XXX
が追記されます。
このtypedには種類があるらしく、Type Annotationsに説明があります。
説明ではイメージが付きにくかったので、雑なサンプルコードを用意して動きを確認したいと思います。
typed: ignore
その名の通り、Sorbetはそのファイルの型チェックを無視します。
エラーの表示はされません。
# typed: ignore
class Test
sig {params(x: Integer).returns(Integer)} # yの型宣言がない
def sum_i(x, y)
x + y.to_i
end
end
$ srb tc
No errors! Great job.
typed: false
シンタックス、定数エラー、シグネチャの構文のみチェックします。
before
# typed: false
class Test
sig {params(x: Integer).returns(Integer)} # yの型宣言がない
def sum_i(x, y)
x + y.to_i
end
end
$ srb tc
test.rb:4: Malformed sig. Type not specified for argument y https://srb.help/5003
4 | def sum_i(x, y)
^
test.rb:3: Signature
3 | sig {params(x: Integer).returns(Integer)} # yの型宣言がない
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Errors: 1
after
# typed: false
class Test
sig {params(x: Integer, y: Float).returns(Integer)}
def sum_i(x, y)
x + y.to_i
end
end
$ srb tc
No errors! Great job.
typed: true
"type erros" と呼ばれる通常タイプのエラーをチェックします。
存在しないメソッドの呼び出し、引数の数が一致しないメソッドの呼び出し、型と矛盾する変数の使用などが含まれます。
before
# typed: true
class Test
sig {params(x: Integer, y: Float).returns(Integer)}
def sum_i(x, y)
x + y.to_i
end
end
@a = Test.new
p @a.sum_i(1, 2) # Floatではない
$ srb tc
test.rb:10: Integer(2) does not match Float for argument y https://srb.help/7002
10 |p @a.sum_i(1, 2)
^^^^^^^^^^^^^^
test.rb:3: Method Test#sum_i has specified y as Float
3 | sig {params(x: Integer, y: Float).returns(Integer)}
^
Got Integer(2) originating from:
test.rb:10:
10 |p @a.sum_i(1, 2) # Floatではない
^
Errors: 1
after
# typed: true
class Test
sig {params(x: Integer, y: Float).returns(Integer)}
def sum_i(x, y)
x + y.to_i
end
end
@a = Test.new
p @a.sum_i(1, 2.0)
$ srb tc
No errors! Great job.
typed: strict
全ての定数、メソッドにシグネチャが付いているかチェックします。
また、全ての定数とインスタンス変数に型注釈が付いているかチェックします。
before
# typed: strict
class Test
sig {params(x: Integer, y: Float).returns(Integer)}
def sum_i(x, y)
x + y.to_i
end
end
@a = Test.new # @aに型注釈を記述していない
p @a.sum_i(1, 2.0)
$ srb tc
test.rb:9: Use of undeclared variable @a https://srb.help/6002
9 |@a = Test.new # @aに型注釈を記述していない
^^
Errors: 1
after
# typed: strict
class Test
sig {params(x: Integer, y: Float).returns(Integer)}
def sum_i(x, y)
x + y.to_i
end
end
@a = T.let(Test.new, T.untyped)
p @a.sum_i(1, 2.0)
$ srb tc
No errors! Great job.
typed: strong
T.untypedの呼び出しもダメ!
before
# typed: strong
class Test
sig {params(x: Integer, y: Float).returns(Integer)}
def sum_i(x, y)
x + y.to_i
end
end
@a = T.let(Test.new, T.untyped) # T.untypedを使用
p @a.sum_i(1, 2.0)
$ srb tc
test.rb:9: This code is untyped https://srb.help/7018
9 |@a = T.let(Test.new, T.untyped)
^^^^^^^^^
test.rb:10: This code is untyped https://srb.help/7018
10 |p @a.sum_i(1, 2.0)
^^^^^^^^^^^^^^^^
Errors: 2
after
# typed: strong
class Test
sig {params(x: Integer, y: Float).returns(Integer)}
def sum_i(x, y)
x + y.to_i
end
end
@a = T.let(Test.new, Test)
p @a.sum_i(1, 2.0)
$ srb tc
No errors! Great job.
まとめ
基本はtyped: true
かtyped: strict
を使用して、T.untyped
は多用しない方が良さそう。