Skip to content

Commit f6a1605

Browse files
committed
refactor: clean up typing with generics
1 parent a350b57 commit f6a1605

18 files changed

+125
-79
lines changed

src/Common/Contracts/WithJsonSerialization.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
* Interface for objects that support JSON serialization and deserialization.
1111
*
1212
* @since 1.0.0
13+
*
14+
* @template TJsonShape of array<string, mixed>
1315
*/
1416
interface WithJsonSerialization extends JsonSerializable
1517
{
@@ -18,8 +20,8 @@ interface WithJsonSerialization extends JsonSerializable
1820
*
1921
* @since 1.0.0
2022
*
21-
* @param array<string, mixed> $json The JSON data.
22-
* @return self The created instance.
23+
* @param TJsonShape $json The JSON data.
24+
* @return static The created instance.
2325
*/
2426
public static function fromJson(array $json);
2527
}

src/Files/DTO/File.php

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
* and handles them appropriately.
1717
*
1818
* @since n.e.x.t
19+
*
20+
* @phpstan-type FileJsonShape array{
21+
* fileType: string,
22+
* url?: string,
23+
* mimeType?: string,
24+
* base64Data?: string
25+
* }
26+
*
27+
* @implements WithJsonSerialization<FileJsonShape>
1928
*/
2029
class File implements WithJsonSchemaInterface, WithJsonSerialization
2130
{
@@ -406,25 +415,23 @@ public function jsonSerialize(): array
406415
* {@inheritDoc}
407416
*
408417
* @since n.e.x.t
409-
*
410-
* @param array{fileType: string, url?: string, mimeType?: string, base64Data?: string} $json The JSON data.
411418
*/
412419
public static function fromJson(array $json): File
413420
{
414-
$fileType = FileTypeEnum::from((string) $json['fileType']);
421+
$fileType = FileTypeEnum::from($json['fileType']);
415422

416423
if ($fileType->isRemote()) {
417424
if (!isset($json['url']) || !isset($json['mimeType'])) {
418425
throw new \InvalidArgumentException('Remote file requires url and mimeType.');
419426
}
420-
return new self((string) $json['url'], (string) $json['mimeType']);
427+
return new self($json['url'], $json['mimeType']);
421428
} else {
422429
if (!isset($json['mimeType']) || !isset($json['base64Data'])) {
423430
throw new \InvalidArgumentException('Inline file requires mimeType and base64Data.');
424431
}
425432
// Create data URI from base64 data and mime type
426-
$mimeType = (string) $json['mimeType'];
427-
$base64Data = (string) $json['base64Data'];
433+
$mimeType = $json['mimeType'];
434+
$base64Data = $json['base64Data'];
428435
$dataUri = sprintf('data:%s;base64,%s', $mimeType, $base64Data);
429436
return new self($dataUri);
430437
}

src/Messages/DTO/Message.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
* containing a role and one or more parts with different content types.
1616
*
1717
* @since n.e.x.t
18+
*
19+
* @phpstan-import-type MessagePartJsonShape from MessagePart
20+
*
21+
* @phpstan-type MessageJsonShape array{
22+
* role: string,
23+
* parts: array<MessagePartJsonShape>
24+
* }
25+
*
26+
* @implements WithJsonSerialization<MessageJsonShape>
1827
*/
1928
class Message implements WithJsonSchemaInterface, WithJsonSerialization
2029
{
@@ -113,13 +122,10 @@ public function jsonSerialize(): array
113122
* {@inheritDoc}
114123
*
115124
* @since n.e.x.t
116-
*
117-
* @param array{role: string, parts: array<array<string, mixed>>} $json The JSON data.
118125
*/
119126
public static function fromJson(array $json): Message
120127
{
121-
$role = MessageRoleEnum::from((string) $json['role']);
122-
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
128+
$role = MessageRoleEnum::from($json['role']);
123129
$partsData = $json['parts'];
124130
$parts = array_map(function (array $partData) {
125131
return MessagePart::fromJson($partData);

src/Messages/DTO/MessagePart.php

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@
1818
* function calls, etc. This DTO encapsulates one such part.
1919
*
2020
* @since n.e.x.t
21+
*
22+
* @phpstan-import-type FileJsonShape from File
23+
* @phpstan-import-type FunctionCallJsonShape from FunctionCall
24+
* @phpstan-import-type FunctionResponseJsonShape from FunctionResponse
25+
*
26+
* @phpstan-type MessagePartJsonShape array{
27+
* type: string,
28+
* text?: string,
29+
* file?: FileJsonShape,
30+
* functionCall?: FunctionCallJsonShape,
31+
* functionResponse?: FunctionResponseJsonShape
32+
* }
33+
*
34+
* @implements WithJsonSerialization<MessagePartJsonShape>
2135
*/
2236
class MessagePart implements WithJsonSchemaInterface, WithJsonSerialization
2337
{
@@ -232,47 +246,36 @@ public function jsonSerialize(): array
232246
* {@inheritDoc}
233247
*
234248
* @since n.e.x.t
235-
*
236-
* @param array{
237-
* type: string,
238-
* text?: string,
239-
* file?: array<string, mixed>,
240-
* functionCall?: array<string, mixed>,
241-
* functionResponse?: array<string, mixed>
242-
* } $json The JSON data.
243249
*/
244250
public static function fromJson(array $json): MessagePart
245251
{
246-
$type = MessagePartTypeEnum::from((string) $json['type']);
252+
$type = MessagePartTypeEnum::from($json['type']);
247253

248254
if ($type->isText()) {
249255
if (!isset($json['text'])) {
250256
throw new \InvalidArgumentException('Text message part requires text field.');
251257
}
252-
return new self((string) $json['text']);
258+
return new self($json['text']);
253259
} elseif ($type->isFile()) {
254260
if (!isset($json['file'])) {
255261
throw new \InvalidArgumentException('File message part requires file field.');
256262
}
257-
/** @var array{fileType: string, url?: string, mimeType?: string, base64Data?: string} $fileData */
258263
$fileData = $json['file'];
259264
return new self(File::fromJson($fileData));
260265
} elseif ($type->isFunctionCall()) {
261266
if (!isset($json['functionCall'])) {
262267
throw new \InvalidArgumentException('Function call message part requires functionCall field.');
263268
}
264-
/** @var array{id?: string, name?: string, args?: mixed} $functionCallData */
265269
$functionCallData = $json['functionCall'];
266270
return new self(FunctionCall::fromJson($functionCallData));
267271
} elseif ($type->isFunctionResponse()) {
268272
if (!isset($json['functionResponse'])) {
269273
throw new \InvalidArgumentException('Function response message part requires functionResponse field.');
270274
}
271-
/** @var array{id: string, name: string, response: mixed} $functionResponseData */
272275
$functionResponseData = $json['functionResponse'];
273276
return new self(FunctionResponse::fromJson($functionResponseData));
274277
}
275278

276-
throw new \InvalidArgumentException(sprintf('Unknown message part type: %s', (string) $json['type']));
279+
throw new \InvalidArgumentException(sprintf('Unknown message part type: %s', $json['type']));
277280
}
278281
}

src/Messages/DTO/ModelMessage.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public function __construct(array $parts)
3535
*/
3636
public static function fromJson(array $json): ModelMessage
3737
{
38-
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
3938
$partsData = $json['parts'];
4039
$parts = array_map(function (array $partData) {
4140
return MessagePart::fromJson($partData);

src/Messages/DTO/SystemMessage.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public function __construct(array $parts)
3535
*/
3636
public static function fromJson(array $json): SystemMessage
3737
{
38-
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
3938
$partsData = $json['parts'];
4039
$parts = array_map(function (array $partData) {
4140
return MessagePart::fromJson($partData);

src/Messages/DTO/UserMessage.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ public function __construct(array $parts)
3434
*/
3535
public static function fromJson(array $json): UserMessage
3636
{
37-
/** @var array<array{type: string, text?: string, file?: array<string, mixed>, functionCall?: array<string, mixed>, functionResponse?: array<string, mixed>}> $partsData */
3837
$partsData = $json['parts'];
3938
$parts = array_map(function (array $partData) {
4039
return MessagePart::fromJson($partData);

src/Operations/Contracts/OperationInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* They provide a way to track the progress and retrieve results asynchronously.
1616
*
1717
* @since n.e.x.t
18+
*
19+
* @extends WithJsonSerialization<array<string, mixed>>
1820
*/
1921
interface OperationInterface extends WithJsonSchemaInterface, WithJsonSerialization
2022
{

src/Operations/DTO/GenerativeAiOperation.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
* immediately, providing access to the result once available.
1616
*
1717
* @since n.e.x.t
18+
*
19+
* @phpstan-import-type GenerativeAiResultJsonShape from GenerativeAiResult
20+
*
21+
* @phpstan-type GenerativeAiOperationJsonShape array{id: string, state: string, result?: GenerativeAiResultJsonShape}
22+
*
23+
* @implements WithJsonSerialization<GenerativeAiOperationJsonShape>
1824
*/
1925
class GenerativeAiOperation implements OperationInterface
2026
{
@@ -158,19 +164,16 @@ public function jsonSerialize(): array
158164
* {@inheritDoc}
159165
*
160166
* @since n.e.x.t
161-
*
162-
* @param array{id: string, state: string, result?: array<string, mixed>} $json The JSON data.
163167
*/
164168
public static function fromJson(array $json): GenerativeAiOperation
165169
{
166-
$state = OperationStateEnum::from((string) $json['state']);
170+
$state = OperationStateEnum::from($json['state']);
167171
$result = null;
168172
if (isset($json['result'])) {
169-
/** @var array{id: string, candidates: array<array<string, mixed>>, tokenUsage: array<string, mixed>, providerMetadata?: array<string, mixed>} $resultData */
170173
$resultData = $json['result'];
171174
$result = GenerativeAiResult::fromJson($resultData);
172175
}
173176

174-
return new self((string) $json['id'], $state, $result);
177+
return new self($json['id'], $state, $result);
175178
}
176179
}

src/Results/Contracts/ResultInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* such as token usage and provider-specific information.
1616
*
1717
* @since n.e.x.t
18+
*
19+
* @extends WithJsonSerialization<array<string, mixed>>
1820
*/
1921
interface ResultInterface extends WithJsonSchemaInterface, WithJsonSerialization
2022
{

0 commit comments

Comments
 (0)