Skip to content

Commit 62a0dab

Browse files
committed
[TypeInfo] Add ArrayShapeType::$sealed
1 parent d768193 commit 62a0dab

File tree

6 files changed

+28
-6
lines changed

6 files changed

+28
-6
lines changed

src/Symfony/Component/TypeInfo/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CHANGELOG
1111
* Add type alias support in `TypeContext` and `StringTypeResolver`
1212
* Add `CollectionType::mergeCollectionValueTypes()` method
1313
* Add `ArrayShapeType` to represent the exact shape of an array
14+
* Add `ArrayShapeType::$sealed` to represent array shape with extra keys
1415

1516
7.2
1617
---

src/Symfony/Component/TypeInfo/Tests/Type/ArrayShapeTypeTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public function testAccepts()
7676

7777
$this->assertTrue($type->accepts(['foo' => true]));
7878
$this->assertTrue($type->accepts(['foo' => true, 'bar' => 'string']));
79+
80+
$type = new ArrayShapeType(['foo' => ['type' => Type::bool()]], sealed: false);
81+
82+
$this->assertTrue($type->accepts(['foo' => true, 'other' => 'string']));
7983
}
8084

8185
public function testToString()
@@ -94,5 +98,10 @@ public function testToString()
9498
'bar' => ['type' => Type::string(), 'optional' => true],
9599
]);
96100
$this->assertSame("array{'bar'?: string, 'foo': bool}", (string) $type);
101+
102+
$type = new ArrayShapeType([
103+
'foo' => ['type' => Type::bool()],
104+
], sealed: false);
105+
$this->assertSame("array{'foo': bool, ...}", (string) $type);
97106
}
98107
}

src/Symfony/Component/TypeInfo/Tests/TypeResolver/StringTypeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public static function resolveDataProvider(): iterable
7676
// array shape
7777
yield [Type::arrayShape(['foo' => Type::true(), 1 => Type::false()]), 'array{foo: true, 1: false}'];
7878
yield [Type::arrayShape(['foo' => ['type' => Type::bool(), 'optional' => true]]), 'array{foo?: bool}'];
79+
yield [Type::arrayShape(['foo' => Type::bool()], sealed: false), 'array{foo: bool, ...}'];
7980

8081
// object shape
8182
yield [Type::object(), 'object{foo: true, bar: false}'];

src/Symfony/Component/TypeInfo/Type/ArrayShapeType.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ final class ArrayShapeType extends CollectionType
3131
/**
3232
* @param array<array{type: Type, optional: bool}> $shape
3333
*/
34-
public function __construct(array $shape)
35-
{
34+
public function __construct(
35+
array $shape,
36+
private readonly bool $sealed = true,
37+
) {
3638
$keyTypes = [];
3739
$valueTypes = [];
3840

@@ -66,6 +68,11 @@ public function getShape(): array
6668
return $this->shape;
6769
}
6870

71+
public function isSealed(): bool
72+
{
73+
return $this->sealed;
74+
}
75+
6976
public function accepts(mixed $value): bool
7077
{
7178
if (!\is_array($value)) {
@@ -81,7 +88,7 @@ public function accepts(mixed $value): bool
8188
foreach ($value as $key => $itemValue) {
8289
$valueType = $this->shape[$key]['type'] ?? false;
8390
if (!$valueType) {
84-
return false;
91+
return !$this->sealed;
8592
}
8693

8794
if (!$valueType->accepts($itemValue)) {
@@ -105,6 +112,10 @@ public function __toString(): string
105112
$items[] = \sprintf('%s: %s', $itemKey, $value['type']);
106113
}
107114

115+
if (!$this->sealed) {
116+
$items[] = '...';
117+
}
118+
108119
return \sprintf('array{%s}', implode(', ', $items));
109120
}
110121
}

src/Symfony/Component/TypeInfo/TypeFactoryTrait.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,13 @@ public static function dict(?Type $value = null): CollectionType
198198
/**
199199
* @param array<array{type: Type, optional?: bool}|Type> $shape
200200
*/
201-
public static function arrayShape(array $shape): ArrayShapeType
201+
public static function arrayShape(array $shape, bool $sealed = true): ArrayShapeType
202202
{
203203
return new ArrayShapeType(array_map(static function (array|Type $item): array {
204204
return $item instanceof Type
205205
? ['type' => $item, 'optional' => false]
206206
: ['type' => $item['type'], 'optional' => $item['optional'] ?? false];
207-
}, $shape));
207+
}, $shape), $sealed);
208208
}
209209

210210
/**

src/Symfony/Component/TypeInfo/TypeResolver/StringTypeResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ private function getTypeFromNode(TypeNode $node, ?TypeContext $typeContext): Typ
110110
];
111111
}
112112

113-
return Type::arrayShape($shape);
113+
return Type::arrayShape($shape, $node->sealed);
114114
}
115115

116116
if ($node instanceof ObjectShapeNode) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy