Skip to content

Commit 2778deb

Browse files
committed
added Type::with()
1 parent ff1f0f6 commit 2778deb

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

src/Utils/Type.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,23 @@ public function __toString(): string
155155
}
156156

157157

158+
/**
159+
* Returns a type that accepts both the current type and the given type.
160+
*/
161+
public function with(string|self $type): self
162+
{
163+
$type = is_string($type) ? self::fromString($type) : $type;
164+
return match (true) {
165+
$this->allows($type) => $this,
166+
$type->allows($this) => $type,
167+
default => new self(array_unique(
168+
array_merge($this->isIntersection() ? [$this] : $this->types, $type->isIntersection() ? [$type] : $type->types),
169+
SORT_REGULAR,
170+
), '|'),
171+
};
172+
}
173+
174+
158175
/**
159176
* Returns the array of subtypes that make up the compound type as strings.
160177
* @return array<int, string|string[]>

tests/Utils/Type.with.phpt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/**
4+
* Test: Nette\Utils\Type::with()
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Nette\Utils\Type;
10+
use Tester\Assert;
11+
12+
require __DIR__ . '/../bootstrap.php';
13+
14+
15+
class Foo
16+
{
17+
}
18+
19+
class FooChild extends Foo
20+
{
21+
}
22+
23+
24+
function testTypeHint(string $expected, Type $type): void
25+
{
26+
Assert::same($expected, (string) $type);
27+
}
28+
29+
30+
testTypeHint('string|int', Type::fromString('string')->with('int'));
31+
testTypeHint('string|int|null', Type::fromString('string')->with('?int'));
32+
testTypeHint('string|int|null', Type::fromString('?string')->with('int'));
33+
testTypeHint('string|int|null', Type::fromString('?string')->with('?int'));
34+
testTypeHint('string|int|bool', Type::fromString('string|int')->with('bool'));
35+
testTypeHint('string|int|bool', Type::fromString('string|int')->with('bool|int'));
36+
testTypeHint('(Foo&Bar)|string', Type::fromString('Foo&Bar')->with('string'));
37+
testTypeHint('Foo', Type::fromString('Foo&Bar')->with('Foo'));
38+
testTypeHint('string|(Foo&Bar)', Type::fromString('string')->with('Foo&Bar'));
39+
testTypeHint('(Foo&Bar)|(Foo&FooChild)', Type::fromString('Foo&Bar')->with('Foo&FooChild'));
40+
testTypeHint('(Foo&Bar)|string|int', Type::fromString('(Foo&Bar)|string')->with('int'));
41+
42+
// with Type object
43+
testTypeHint('string|int', Type::fromString('string')->with(Type::fromString('int')));
44+
45+
// mixed
46+
testTypeHint('mixed', Type::fromString('string')->with('mixed'));
47+
testTypeHint('mixed', Type::fromString('mixed')->with('null'));
48+
49+
// Already allows - returns same instance
50+
$type = Type::fromString('string');
51+
Assert::same($type, $type->with('string'));
52+
53+
$type = Type::fromString('string|int|bool');
54+
Assert::same($type, $type->with('int'));
55+
56+
$type = Type::fromString('?string');
57+
Assert::same($type, $type->with('string'));
58+
Assert::same($type, $type->with('null'));
59+
60+
$with = Type::fromString('mixed');
61+
Assert::same($with, Type::fromString('string')->with($with));
62+
63+
$type = Type::fromString('Foo|Bar');
64+
Assert::same($type, $type->with('FooChild'));
65+
66+
$with = Type::fromString('Foo');
67+
Assert::same($with, Type::fromString('Foo&Bar')->with($with));

0 commit comments

Comments
 (0)