literal 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/literal/array.rb +15 -15
  3. data/lib/literal/data_structure.rb +4 -3
  4. data/lib/literal/delegator.rb +25 -0
  5. data/lib/literal/enum.rb +4 -5
  6. data/lib/literal/flags/flags_16.rb +7 -0
  7. data/lib/literal/flags/flags_32.rb +7 -0
  8. data/lib/literal/flags/flags_64.rb +7 -0
  9. data/lib/literal/flags/flags_8.rb +7 -0
  10. data/lib/literal/flags.rb +0 -24
  11. data/lib/literal/hash.rb +1 -1
  12. data/lib/literal/properties/schema.rb +3 -3
  13. data/lib/literal/properties.rb +5 -6
  14. data/lib/literal/property.rb +3 -3
  15. data/lib/literal/rails/enum_type.rb +4 -0
  16. data/lib/literal/rails.rb +0 -3
  17. data/lib/literal/set.rb +1 -1
  18. data/lib/literal/transforms.rb +2 -2
  19. data/lib/literal/tuple.rb +2 -2
  20. data/lib/literal/types/array_type.rb +1 -0
  21. data/lib/literal/types/class_type.rb +3 -2
  22. data/lib/literal/types/constraint_type.rb +5 -4
  23. data/lib/literal/{deferred_type.rb → types/deferred_type.rb} +1 -1
  24. data/lib/literal/types/descendant_type.rb +2 -1
  25. data/lib/literal/types/enumerable_type.rb +2 -1
  26. data/lib/literal/types/frozen_type.rb +3 -2
  27. data/lib/literal/types/hash_type.rb +3 -2
  28. data/lib/literal/types/interface_type.rb +20 -14
  29. data/lib/literal/types/intersection_type.rb +4 -3
  30. data/lib/literal/types/map_type.rb +2 -1
  31. data/lib/literal/types/nilable_type.rb +3 -2
  32. data/lib/literal/types/not_type.rb +4 -3
  33. data/lib/literal/types/predicate_type.rb +22 -0
  34. data/lib/literal/types/range_type.rb +2 -1
  35. data/lib/literal/types/set_type.rb +2 -1
  36. data/lib/literal/types/tuple_type.rb +1 -0
  37. data/lib/literal/types/union_type.rb +46 -30
  38. data/lib/literal/types.rb +143 -87
  39. data/lib/literal/value.rb +65 -0
  40. data/lib/literal/version.rb +1 -1
  41. data/lib/literal.rb +82 -37
  42. metadata +26 -5
@@ -8,6 +8,7 @@ class Literal::Types::IntersectionType
8
8
  raise Literal::ArgumentError.new("_Intersection type must have at least one type.") if types.size < 1
9
9
 
10
10
  @types = types
11
+ freeze
11
12
  end
12
13
 
13
14
  attr_reader :types
@@ -35,17 +36,17 @@ class Literal::Types::IntersectionType
35
36
  when Literal::Types::IntersectionType
36
37
  @types.all? do |type|
37
38
  other.types.any? do |other_type|
38
- Literal.subtype?(other_type, of: type)
39
+ Literal.subtype?(other_type, type)
39
40
  end
40
41
  end
41
42
  when Literal::Types::ConstraintType
42
43
  @types.all? do |type|
43
44
  other.object_constraints.any? do |object_constraint|
44
- Literal.subtype?(object_constraint, of: type)
45
+ Literal.subtype?(object_constraint, type)
45
46
  end
46
47
  end
47
48
  when Literal::Types::FrozenType
48
- @types.all? { |type| Literal.subtype?(other.type, of: type) }
49
+ @types.all? { |type| Literal.subtype?(other.type, type) }
49
50
  else
50
51
  false
51
52
  end
@@ -6,6 +6,7 @@ class Literal::Types::MapType
6
6
 
7
7
  def initialize(**shape)
8
8
  @shape = shape
9
+ freeze
9
10
  end
10
11
 
11
12
  attr_reader :shape
@@ -44,7 +45,7 @@ class Literal::Types::MapType
44
45
  other_shape = other.shape
45
46
 
46
47
  @shape.all? do |k, v|
47
- Literal.subtype?(other_shape[k], of: v)
48
+ Literal.subtype?(other_shape[k], v)
48
49
  end
49
50
  else
50
51
  false
@@ -6,6 +6,7 @@ class Literal::Types::NilableType
6
6
 
7
7
  def initialize(type)
8
8
  @type = type
9
+ freeze
9
10
  end
10
11
 
11
12
  attr_reader :type
@@ -25,11 +26,11 @@ class Literal::Types::NilableType
25
26
  def >=(other)
26
27
  case other
27
28
  when Literal::Types::NilableType
28
- Literal.subtype?(other.type, of: @type)
29
+ Literal.subtype?(other.type, @type)
29
30
  when nil
30
31
  true
31
32
  else
32
- Literal.subtype?(other, of: @type)
33
+ Literal.subtype?(other, @type)
33
34
  end
34
35
  end
35
36
 
@@ -6,6 +6,7 @@ class Literal::Types::NotType
6
6
 
7
7
  def initialize(type)
8
8
  @type = type
9
+ freeze
9
10
  end
10
11
 
11
12
  attr_reader :type
@@ -21,11 +22,11 @@ class Literal::Types::NotType
21
22
  def >=(other)
22
23
  case other
23
24
  when Literal::Types::NotType
24
- Literal.subtype?(other.type, of: @type)
25
+ Literal.subtype?(other.type, @type)
25
26
  when Literal::Types::ConstraintType
26
- other.object_constraints.any? { |constraint| Literal.subtype?(constraint, of: self) }
27
+ other.object_constraints.any? { |constraint| Literal.subtype?(constraint, self) }
27
28
  when Literal::Types::IntersectionType
28
- other.types.any? { |type| Literal.subtype?(type, of: self) }
29
+ other.types.any? { |type| Literal.subtype?(type, self) }
29
30
  else
30
31
  false
31
32
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Literal::Types::PredicateType
4
+ include Literal::Type
5
+
6
+ def initialize(message:, block:)
7
+ @message = message
8
+ @block = block
9
+
10
+ freeze
11
+ end
12
+
13
+ def inspect
14
+ %(_Predicate("#{@message}"))
15
+ end
16
+
17
+ def ===(other)
18
+ @block === other
19
+ end
20
+
21
+ freeze
22
+ end
@@ -6,6 +6,7 @@ class Literal::Types::RangeType
6
6
 
7
7
  def initialize(type)
8
8
  @type = type
9
+ freeze
9
10
  end
10
11
 
11
12
  attr_reader :type
@@ -27,7 +28,7 @@ class Literal::Types::RangeType
27
28
  def >=(other)
28
29
  case other
29
30
  when Literal::Types::RangeType
30
- Literal.subtype?(other.type, of: @type)
31
+ Literal.subtype?(other.type, @type)
31
32
  else
32
33
  false
33
34
  end
@@ -6,6 +6,7 @@ class Literal::Types::SetType
6
6
 
7
7
  def initialize(type)
8
8
  @type = type
9
+ freeze
9
10
  end
10
11
 
11
12
  attr_reader :type
@@ -37,7 +38,7 @@ class Literal::Types::SetType
37
38
  def >=(other)
38
39
  case other
39
40
  when Literal::Types::SetType
40
- Literal.subtype?(other.type, of: @type)
41
+ Literal.subtype?(other.type, @type)
41
42
  else
42
43
  false
43
44
  end
@@ -8,6 +8,7 @@ class Literal::Types::TupleType
8
8
  raise Literal::ArgumentError.new("_Tuple type must have at least one type.") if types.size < 1
9
9
 
10
10
  @types = types
11
+ freeze
11
12
  end
12
13
 
13
14
  attr_reader :types
@@ -2,74 +2,90 @@
2
2
 
3
3
  class Literal::Types::UnionType
4
4
  include Enumerable
5
+ include Literal::Type
5
6
 
6
- def initialize(*types)
7
- raise Literal::ArgumentError.new("_Union type must have at least one type.") if types.size < 1
7
+ def initialize(*queue)
8
+ raise Literal::ArgumentError.new("_Union type must have at least one type.") if queue.size < 1
9
+ types = []
10
+ primitives = Set[]
11
+
12
+ while queue.length > 0
13
+ type = queue.shift
14
+ case type
15
+ when Literal::Types::UnionType
16
+ queue.concat(type.types, type.primitives.to_a)
17
+ when Array, Hash, String, Symbol, Integer, Float, Complex, Rational, true, false, nil
18
+ primitives << type
19
+ else
20
+ types << type
21
+ end
22
+ end
23
+
24
+ types.uniq!
25
+ @types = types
26
+ @primitives = primitives
8
27
 
9
- @types = []
10
- load_types(types)
11
- @types.uniq!
12
28
  @types.freeze
29
+ @primitives.freeze
30
+ freeze
13
31
  end
14
32
 
15
- attr_reader :types
33
+ attr_reader :types, :primitives
16
34
 
17
35
  def inspect
18
- "_Union(#{@types.inspect})"
36
+ "_Union(#{to_a.map(&:inspect).join(', ')})"
19
37
  end
20
38
 
21
39
  def ===(value)
40
+ return true if @primitives.include?(value)
41
+
22
42
  types = @types
43
+
23
44
  i, len = 0, types.size
24
45
  while i < len
25
46
  return true if types[i] === value
26
47
  i += 1
27
48
  end
49
+
50
+ false
28
51
  end
29
52
 
30
53
  def each(&)
54
+ @primitives.each(&)
31
55
  @types.each(&)
32
56
  end
33
57
 
34
58
  def deconstruct
35
- @types.to_a
59
+ to_a
36
60
  end
37
61
 
38
62
  def [](key)
39
- if @types.include?(key)
63
+ if @primitives.include?(key) || @types.include?(key)
40
64
  key
41
- else
42
- raise ArgumentError.new("#{key} not in #{inspect}")
43
65
  end
44
66
  end
45
67
 
46
- def record_literal_type_errors(ctx)
47
- @types.each do |type|
48
- ctx.add_child(label: type.inspect, expected: type, actual: ctx.actual)
49
- end
50
- ctx.children.clear if ctx.children.none? { |c| c.children.any? }
68
+ def fetch(key)
69
+ self[key] or raise KeyError.new("Key not found: #{key.inspect}")
51
70
  end
52
71
 
53
72
  def >=(other)
73
+ types = @types
74
+ primitives = @primitives
75
+
54
76
  case other
55
77
  when Literal::Types::UnionType
56
- other.types.all? do |other_type|
57
- @types.any? do |type|
58
- Literal.subtype?(type, of: other_type)
59
- end
60
- end
61
- else
62
- @types.any? do |type|
63
- Literal.subtype?(other, of: type)
78
+ types_have_at_least_one_subtype = other.types.all? do |other_type|
79
+ primitives.any? { |p| Literal.subtype?(other_type, p) } || types.any? { |t| Literal.subtype?(other_type, t) }
64
80
  end
65
- end
66
- end
67
81
 
68
- private
82
+ primitives_have_at_least_one_subtype = other.primitives.all? do |other_primitive|
83
+ primitives.any? { |p| Literal.subtype?(other_primitive, p) } || types.any? { |t| Literal.subtype?(other_primitive, t) }
84
+ end
69
85
 
70
- def load_types(types)
71
- types.each do |type|
72
- (Literal::Types::UnionType === type) ? load_types(type.types) : @types << type
86
+ types_have_at_least_one_subtype && primitives_have_at_least_one_subtype
87
+ else
88
+ types.any? { |t| Literal.subtype?(other, t) } || primitives.any? { |p| Literal.subtype?(other, p) }
73
89
  end
74
90
  end
75
91
 
data/lib/literal/types.rb CHANGED
@@ -1,150 +1,177 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Literal::Types
4
- autoload :AnyType, "literal/types/any_type"
5
- autoload :ArrayType, "literal/types/array_type"
6
- autoload :BooleanType, "literal/types/boolean_type"
7
- autoload :ClassType, "literal/types/class_type"
8
- autoload :ConstraintType, "literal/types/constraint_type"
9
- autoload :DeferredType, "literal/deferred_type"
10
- autoload :DescendantType, "literal/types/descendant_type"
11
- autoload :EnumerableType, "literal/types/enumerable_type"
12
- autoload :FalsyType, "literal/types/falsy_type"
13
- autoload :FrozenType, "literal/types/frozen_type"
14
- autoload :HashType, "literal/types/hash_type"
15
- autoload :InterfaceType, "literal/types/interface_type"
16
- autoload :IntersectionType, "literal/types/intersection_type"
17
- autoload :JSONDataType, "literal/types/json_data_type"
18
- autoload :MapType, "literal/types/map_type"
19
- autoload :NeverType, "literal/types/never_type"
20
- autoload :NilableType, "literal/types/nilable_type"
21
- autoload :NotType, "literal/types/not_type"
22
- autoload :RangeType, "literal/types/range_type"
23
- autoload :SetType, "literal/types/set_type"
24
- autoload :TruthyType, "literal/types/truthy_type"
25
- autoload :TupleType, "literal/types/tuple_type"
26
- autoload :UnionType, "literal/types/union_type"
27
- autoload :VoidType, "literal/types/void_type"
28
-
29
- ProcableType = InterfaceType.new(:to_proc).freeze
30
- CallableType = InterfaceType.new(:call).freeze
31
- LambdaType = ConstraintType.new(Proc, lambda?: true).freeze
32
-
33
- NilableBooleanType = NilableType.new(BooleanType::Instance).freeze
34
- NilableCallableType = NilableType.new(CallableType).freeze
35
- NilableJSONDataType = NilableType.new(JSONDataType).freeze
36
- NilableLambdaType = NilableType.new(LambdaType).freeze
37
- NilableProcableType = NilableType.new(ProcableType).freeze
4
+ extend self
38
5
 
39
6
  # Matches any value except `nil`. Use `_Any?` or `_Void` to match any value including `nil`.
7
+ # ```ruby
8
+ # _Any
9
+ # ```
40
10
  def _Any
41
11
  AnyType::Instance
42
12
  end
43
13
 
14
+ # Matches any value including `nil`. This is the same as `_Void` and the opposite of `_Never`.
15
+ # ```ruby
16
+ # _Any?
17
+ # ```
44
18
  def _Any?
45
19
  VoidType::Instance
46
20
  end
47
21
 
48
- # Matches if the value is an `Array` and all the elements match the given type.
49
- def _Array(...)
50
- ArrayType.new(...)
22
+ # Matches if the value is an `Array` and all the elements of the array match the given type.
23
+ # ```ruby
24
+ # _Array(String)
25
+ # ```
26
+ def _Array(type)
27
+ ArrayType.new(type)
51
28
  end
52
29
 
53
- # Nilable version of `_Array`
54
- def _Array?(...)
55
- NilableType.new(
56
- ArrayType.new(...)
30
+ # Nilable version of `_Array`.
31
+ # ```ruby
32
+ # _Array?(String)
33
+ # ```
34
+ def _Array?(type)
35
+ _Nilable(
36
+ _Array(type)
57
37
  )
58
38
  end
59
39
 
60
- # Matches if the value is `true` or `false`.
40
+ # Matches if the value is either `true` or `false`. This is equivalent to `_Union(true, false)`.
41
+ # ```ruby
42
+ # _Boolean
43
+ # ```
61
44
  def _Boolean
62
45
  BooleanType::Instance
63
46
  end
64
47
 
65
- # Nilable version of `_Boolean`
48
+ # Nilable version of `_Boolean`.
49
+ # ```ruby
50
+ # _Boolean?
51
+ # ```
66
52
  def _Boolean?
67
53
  NilableBooleanType
68
54
  end
69
55
 
70
56
  # Matches if the value responds to `#call`.
57
+ # ```ruby
58
+ # _Callable
59
+ # ```
71
60
  def _Callable
72
61
  CallableType
73
62
  end
74
63
 
75
- # Nilabl version of `_Callable`
64
+ # Nilable version of `_Callable`.
65
+ # ```ruby
66
+ # _Callable?
67
+ # ```
76
68
  def _Callable?
77
69
  NilableCallableType
78
70
  end
79
71
 
80
72
  # Matches if the value either the given class or a subclass of it.
81
- def _Class(...)
82
- ClassType.new(...)
73
+ # ```ruby
74
+ # _Class(ActiveRecord::Base)
75
+ # ```
76
+ def _Class(expected_class)
77
+ ClassType.new(expected_class)
83
78
  end
84
79
 
85
- # Nilable version of `_Class`
80
+ # Nilable version of `_Class`.
81
+ # ```ruby
82
+ # _Class?(ActiveRecord::Base)
83
+ # ```
86
84
  def _Class?(...)
87
- NilableType.new(
88
- ClassType.new(...)
85
+ _Nilable(
86
+ _Class(...)
89
87
  )
90
88
  end
91
89
 
92
90
  # Similar to `_Intersection`, but allows you to specify attribute constraints as keyword arguments.
93
- # @example
94
- # _Constraint(Array, size: 1..3)
95
- def _Constraint(...)
96
- ConstraintType.new(...)
91
+ # ```ruby
92
+ # _Constraint(Array, size: 1..3)
93
+ # ```
94
+ def _Constraint(*a, **k)
95
+ if a.length == 1 && k.length == 0
96
+ a[0]
97
+ else
98
+ ConstraintType.new(*a, **k)
99
+ end
97
100
  end
98
101
 
99
102
  # Nilable version of `_Constraint`
103
+ # ```ruby
104
+ # _Constraint?(Array, size: 1..3)
105
+ # ```
100
106
  def _Constraint?(...)
101
- NilableType.new(
102
- ConstraintType.new(...)
107
+ _Nilable(
108
+ _Constraint(...)
103
109
  )
104
110
  end
105
111
 
106
112
  # Matches if the value is a `Date` and matches the given constraints.
107
- # If you don't need any constraints, use `Date` instead of `_Date`.
113
+ # If you don't need any constraints, use `Date` instead of `_Date`. See also `_Constraint`.
114
+ # ```ruby
115
+ # _Date((Date.today)..)
116
+ # _Date(year: 2025)
117
+ # ```
108
118
  def _Date(...)
109
119
  _Constraint(Date, ...)
110
120
  end
111
121
 
112
- # Nilable version of `_Date`
122
+ # Nilable version of `_Date`.
113
123
  def _Date?(...)
114
124
  _Nilable(
115
125
  _Date(...)
116
126
  )
117
127
  end
118
128
 
119
- def _Deferred(...)
120
- DeferredType.new(...)
129
+ # Takes a type as a block so it can be resolved when needed. This is useful if declaring your type now would cause an error because constants haven’t been defined yet.
130
+ # ```ruby
131
+ # _Deferred { _Class(SomeFutureConstant) }
132
+ # ```
133
+ def _Deferred(&type)
134
+ DeferredType.new(&type)
135
+ end
136
+
137
+ # Nilable version of `_Deferred`.
138
+ def _Deferred?(&type)
139
+ _Nilable(
140
+ _Deferred(&type)
141
+ )
121
142
  end
122
143
 
123
144
  # Matches if the value is a descendant of the given class.
145
+ # ```ruby
146
+ # _Descendant(ActiveRecord::Base)
147
+ # ```
124
148
  def _Descendant(...)
125
149
  DescendantType.new(...)
126
150
  end
127
151
 
128
- # Nilable version of `_Descendant`
152
+ # Nilable version of `_Descendant`.
129
153
  def _Descendant?(...)
130
- NilableType.new(
131
- DescendantType.new(...)
154
+ _Nilable(
155
+ _Descendant(...)
132
156
  )
133
157
  end
134
158
 
135
159
  #  Matches if the value is an `Enumerable` and all its elements match the given type.
136
- def _Enumerable(...)
137
- EnumerableType.new(...)
160
+ # ```ruby
161
+ # _Enumerable(String)
162
+ # ```
163
+ def _Enumerable(type)
164
+ EnumerableType.new(type)
138
165
  end
139
166
 
140
- # Nilable version of `_Enumerable`
167
+ # Nilable version of `_Enumerable`.
141
168
  def _Enumerable?(...)
142
- NilableType.new(
143
- EnumerableType.new(...)
169
+ _Nilable(
170
+ _Enumerable(...)
144
171
  )
145
172
  end
146
173
 
147
- # Matches *"falsy"* values (`nil` and `false`).
174
+ # Matches *"falsy"* values (`nil` and `false`). This is equivalent to `_Nilable(false)` or `_Union(nil, false)`.
148
175
  def _Falsy
149
176
  FalsyType::Instance
150
177
  end
@@ -152,11 +179,14 @@ module Literal::Types
152
179
  # Matches if the value is a `Float` and matches the given constraints.
153
180
  # You could use a `Range`, for example, as a constraint.
154
181
  # If you don't need a constraint, use `Float` instead of `_Float`.
182
+ # ```ruby
183
+ # _Float(5..10)
184
+ # ```
155
185
  def _Float(...)
156
186
  _Constraint(Float, ...)
157
187
  end
158
188
 
159
- # Nilable version of `_Float`
189
+ # Nilable version of `_Float`.
160
190
  def _Float?(...)
161
191
  _Nilable(
162
192
  _Float(...)
@@ -170,8 +200,8 @@ module Literal::Types
170
200
 
171
201
  # Nilable version of `_Frozen`
172
202
  def _Frozen?(...)
173
- NilableType.new(
174
- FrozenType.new(...)
203
+ _Nilable(
204
+ _Frozen(...)
175
205
  )
176
206
  end
177
207
 
@@ -182,8 +212,8 @@ module Literal::Types
182
212
 
183
213
  # Nilable version of `_Hash`
184
214
  def _Hash?(...)
185
- NilableType.new(
186
- HashType.new(...)
215
+ _Nilable(
216
+ _Hash(...)
187
217
  )
188
218
  end
189
219
 
@@ -210,8 +240,8 @@ module Literal::Types
210
240
 
211
241
  # Nilable version of `_Interface`
212
242
  def _Interface?(...)
213
- NilableType.new(
214
- InterfaceType.new(...)
243
+ _Nilable(
244
+ _Interface(...)
215
245
  )
216
246
  end
217
247
 
@@ -222,8 +252,8 @@ module Literal::Types
222
252
 
223
253
  # Nilable version of `_Intersection`
224
254
  def _Intersection?(...)
225
- NilableType.new(
226
- IntersectionType.new(...)
255
+ _Nilable(
256
+ _Intersection(...)
227
257
  )
228
258
  end
229
259
 
@@ -247,14 +277,20 @@ module Literal::Types
247
277
  NilableLambdaType
248
278
  end
249
279
 
280
+ # ```ruby
281
+ # _Map(name: String, age: Integer)
282
+ # ```
250
283
  def _Map(...)
251
284
  MapType.new(...)
252
285
  end
253
286
 
254
287
  # Nilable version of `_Map`
288
+ # ```ruby
289
+ # _Map?(name: String, age: Integer)
290
+ # ```
255
291
  def _Map?(...)
256
- NilableType.new(
257
- MapType.new(...)
292
+ _Nilable(
293
+ _Map(...)
258
294
  )
259
295
  end
260
296
 
@@ -278,6 +314,10 @@ module Literal::Types
278
314
  end
279
315
  end
280
316
 
317
+ def _Predicate(message, &block)
318
+ PredicateType.new(message:, block:)
319
+ end
320
+
281
321
  # Matches if the value is a `Proc` or responds to `#to_proc`.
282
322
  def _Procable
283
323
  ProcableType
@@ -295,8 +335,8 @@ module Literal::Types
295
335
 
296
336
  # Nilable version of `_Range`
297
337
  def _Range?(...)
298
- NilableType.new(
299
- RangeType.new(...)
338
+ _Nilable(
339
+ _Range(...)
300
340
  )
301
341
  end
302
342
 
@@ -307,8 +347,8 @@ module Literal::Types
307
347
 
308
348
  # Nilable version of `_Set`
309
349
  def _Set?(...)
310
- NilableType.new(
311
- SetType.new(...)
350
+ _Nilable(
351
+ _Set(...)
312
352
  )
313
353
  end
314
354
 
@@ -356,14 +396,20 @@ module Literal::Types
356
396
  end
357
397
 
358
398
  # Matches if the value is an `Array` and each element matches the given types in order.
399
+ # ```ruby
400
+ # _Tuple(String, Integer, Integer)
401
+ # ```
359
402
  def _Tuple(...)
360
403
  TupleType.new(...)
361
404
  end
362
405
 
363
406
  # Nilable version of `_Typle`
407
+ # ```ruby
408
+ # _Tuple?(String, Integer, Integer)
409
+ # ```
364
410
  def _Tuple?(...)
365
- NilableType.new(
366
- TupleType.new(...)
411
+ _Nilable(
412
+ _Tuple(...)
367
413
  )
368
414
  end
369
415
 
@@ -374,12 +420,22 @@ module Literal::Types
374
420
 
375
421
  # Nilable version of `_Union`
376
422
  def _Union?(...)
377
- NilableType.new(
378
- UnionType.new(...)
423
+ _Nilable(
424
+ _Union(...)
379
425
  )
380
426
  end
381
427
 
382
428
  def _Void
383
429
  VoidType::Instance
384
430
  end
431
+
432
+ ProcableType = _Interface(:to_proc)
433
+ CallableType = _Interface(:call)
434
+ LambdaType = _Constraint(Proc, lambda?: true)
435
+
436
+ NilableBooleanType = _Nilable(BooleanType::Instance)
437
+ NilableCallableType = _Nilable(CallableType)
438
+ NilableJSONDataType = _Nilable(JSONDataType)
439
+ NilableLambdaType = _Nilable(LambdaType)
440
+ NilableProcableType = _Nilable(ProcableType)
385
441
  end