Skip to content

Commit 86d00d7

Browse files
authored
Support union type in Type::nullable (#141)
1 parent 2208eb1 commit 86d00d7

File tree

3 files changed

+43
-8
lines changed

3 files changed

+43
-8
lines changed

readme.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,9 @@ Each type or union/intersection type can be passed as a string, you can also use
536536
use Nette\PhpGenerator\Type;
537537

538538
$member->setType('array'); // or Type::Array;
539-
$member->setType('array|string'); // or Type::union('array', 'string')
539+
$member->setType('?array'); // or Type::nullable(Type::Array);
540+
$member->setType('array|string'); // or Type::union(Type::Array, Type::String)
541+
$member->setType('array|string|null'); // or Type::nullable(Type::union(Type::Array, Type::String))
540542
$member->setType('Foo&Bar'); // or Type::intersection(Foo::class, Bar::class)
541543
$member->setType(null); // removes type
542544
```

src/PhpGenerator/Type.php

+19-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,25 @@ class Type
8585

8686
public static function nullable(string $type, bool $nullable = true): string
8787
{
88-
return ($nullable ? '?' : '') . ltrim($type, '?');
88+
if (! str_contains($type, '|')) {
89+
return ($nullable ? '?' : '') . ltrim($type, '?');
90+
}
91+
92+
// Union type
93+
$types = explode('|', $type);
94+
if (in_array('null', $types)) {
95+
if ($nullable) {
96+
return $type;
97+
}
98+
$types = array_diff($types, ['null']);
99+
} else {
100+
if (!$nullable) {
101+
return $type;
102+
}
103+
$types[] = 'null';
104+
}
105+
106+
return implode('|', $types);
89107
}
90108

91109

tests/PhpGenerator/Type.phpt

+21-6
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,27 @@ use Nette\PhpGenerator\Type;
66
use Tester\Assert;
77
require __DIR__ . '/../bootstrap.php';
88

9+
// Nullable
10+
Assert::same('?int', Type::nullable(Type::Int));
11+
Assert::same('int', Type::nullable(Type::Int, nullable: false));
912

10-
Assert::same('A|string', Type::union(A::class, Type::String));
13+
Assert::same('?int', Type::nullable('?int'));
14+
Assert::same('int', Type::nullable('?int', nullable: false));
15+
16+
Assert::same('int|float|string|null', Type::nullable('int|float|string'));
17+
Assert::same('int|float|string', Type::nullable('int|float|string', nullable: false));
18+
19+
Assert::same('null|int|float|string', Type::nullable('null|int|float|string'));
20+
Assert::same('int|float|string', Type::nullable('null|int|float|string', nullable: false));
1121

12-
Assert::same('?A', Type::nullable(A::class));
13-
Assert::same('?A', Type::nullable(A::class));
14-
Assert::same('A', Type::nullable(A::class, nullable: false));
22+
Assert::same('int|float|string|null', Type::nullable('int|float|string|null'));
23+
Assert::same('int|float|string', Type::nullable('int|float|string|null', nullable: false));
24+
25+
Assert::same('int|float|null|string', Type::nullable('int|float|null|string'));
26+
Assert::same('int|float|string', Type::nullable('int|float|null|string', nullable: false));
27+
28+
// Union
29+
Assert::same('A|string', Type::union(A::class, Type::String));
1530

16-
Assert::same('?A', Type::nullable('?A'));
17-
Assert::same('A', Type::nullable('?A', nullable: false));
31+
// Intersection
32+
Assert::same('A&string', Type::intersection(A::class, Type::String));

0 commit comments

Comments
 (0)