Banning untyped from a file
Note: This feature is in beta. Please give us feedback!
The # typed: strong
sigil bans all usage of T.untyped
in a file.
Writing code at this level can be extremely exacting. We do not recommend using
this level too early in the life cycle of adopting Sorbet, as it can cause an
unreasonably high barrier to entry when changing the codebase in the future.
Frequently, the best approach to dealing with # typed: strong
-level errors is
to simply ignore them, by downgrading the sigil to # typed: strict
.
A better option is to configure Sorbet to highlight untyped code in the editor:
This will give most of the benefits of flagging which code is covered by Sorbet, while not being a large burden.
For more information on our recommendations when adopting Sorbet, see Suggestions for driving adoption.
That being said, we welcome enterprising Sorbet users to try writing code at this level. If you do have feedback for where it’s difficult or impossible to use this level, please let us know.
What counts as a usage of untyped?
Some examples of things that count as a usage of untyped:
- Calling a method on an untyped value
- Passing an untyped value to a method
- Conditionally branching on an untyped value
- Returning an untyped value from a method
- etc.
The list of things that count as usages of untyped will grow over time (which is part of the reason why this feature is considered “beta”).
What doesn’t count?
It’s maybe more interesting to see what doesn’t count as a usage of untyped:
x = T.let(..., SomeType)
where...
is an untyped expression.This is one of the primary ways to fix errors arising in
# typed: strong
files. TheT.let
type assertion ascribes a static type tox
. Usingx
in place of...
means that Sorbet will see a usage of something typed instead of something untyped.Any usage of a type like
T::Array[T.untyped]
orT::Hash[String, T.untyped]
, which hasT.untyped
somewhere inside it.We may reconsider this decision in the future. Sorbet will, at least, flag that usages of elements of these values are usages of untyped:
sig { params(xs: T::Array[T.untyped]).void } def example(xs) x0 = xs.first # (nothing reported here) x0.even? # ^^ Call to method `even?` on `T.untyped` end
Any place where code type checks only because a method parameter accepts
T.untyped
.This is a compromise. There are currently too many methods in the wild which are typed as taking
T.untyped
to mean “I accept all kinds of values.” Sorbet currently lacks syntax to declare when this is intentional vs accidental because a more precise type has not been declared.
T.untyped
?
How can I avoid using It depends on the source of the T.untyped
.
If the untyped comes from a method which returns
T.untyped
, consider adding a signature to that method (or improving the existing signature).If it’s not possible to write a method signature which applies to the method definition, use
T.let
at each call site of the method which returnsT.untyped
to provide a more specific type to the result.If the untyped comes from Sorbet’s RBI files for the standard library, please make a contribution to improve them!
If the untyped comes from other generated RBI files, figure out a way to include generated signatures in the RBI files.
If the untyped comes from a use of
T.unsafe
, either try to remove the call toT.unsafe
and fix any type errors, or replace it withT.cast
, which will be a more limited type system escape hatch thanT.unsafe
.
Ultimately, fixing the error is similar to fixing any other type error.
Why is this feature in beta?
This feature is currently under development, and we’d love your feedback!
In addition to the things documented in the What doesn’t count section above, here are some known limitations:
Sometimes, the region Sorbet displays in the error message does not precisely match the code which is untyped.
For example, a previous version of this feature accidentally underlined an entire block (from
do
untilend
) when the value returned from the block wasT.untyped
. This was fixed by reporting exactly the block’s return value.Please report cases like these!
You can use this Sorbet playground as a starting point to report issues with this feature.
Sometimes, the source of the untyped is Sorbet itself.
Certain features of Ruby are hard to statically type and have historically been supported on a “best effort” basis by marking them
T.untyped
.Feel free to browse our Untyped code milestone to see if it looks like someone has already reported a bug. Otherwise, use this Sorbet playground to craft a test case and report it to us.
Again, to browse the most up-to-date known limitations with this feature, check the Untyped code milestone for the Sorbet project.