SorbetのType Annotations動作確認

Rubyの型解析ライブラリSorbetがリリースされたとの事で[Doc](https://sorbet.org/docs/adopting)を参考に導入に挑戦！
進めていく内にrbファイルに`# typed: XXX`が追記されます。
このtypedには種類があるらしく、[Type Annotations](https://sorbet.org/docs/static#file-level-granularity-strictness-levels)に説明があります。
説明ではイメージが付きにくかったので、雑なサンプルコードを用意して動きを確認したいと思います。
# typed: ignore

その名の通り、Sorbetはそのファイルの型チェックを無視します。
エラーの表示はされません。

```ruby
# 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

```ruby
# 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

```ruby
# 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

```ruby
# 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

```ruby
# 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

```ruby
# 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

```ruby
# 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

```ruby
# 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

```ruby
# 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`は多用しない方が良さそう。