Skip to content

Support type narrowing #1822

@mtsmfm

Description

@mtsmfm

Ref: soutaro/steep#472

Currently RBS doesn't have any syntax to narrow types in control flow.

So there's no way to achieve the following:

a = [1, nil].sample # a is `Integer | nil`
unless a.nil?
  # a is `Integer` here
  p a + 1
end

But actually, both Sorbet and Steep treat some special methods to narrow types

https://github.com/sorbet/sorbet/blob/718bc64f895abeeff88f56efbc92a3554ffaa4f2/infer/environment.cc#L536-L545

https://github.com/soutaro/steep/blob/a868762c2bd09f0954b05cdd9eab1819e14a51d3/lib/steep/interface/builder.rb#L709-L721

Ideally, I think we need to have a syntax considering Ruby gems which extend Object like ActiveSupport's present?.

I'm not very familiar with type system though, I guess the syntax would be similar with TypeScript's type predicates

https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates

class Object[T?]
  def nil?: () -> self is nil
end
class Object[T?]
  def present?: () -> self is T
end

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions