Skip to content

Support for generics in interface inference #270

@arnaud-lb

Description

@arnaud-lb

Thank you for the awesome work on this library. Valinor is super useful and makes it much easier to deal with external data in a strongly typed project.

I am facing an issue since 0.11 added the following restriction:

It is now mandatory to list all possible class-types that can be inferred by the mapper. This change is a step towards the library being able to deliver powerful new features such as compiling a mapper for better performance.

Currently, this change makes interface inference incompatible with generic classes, as Valinor will not accept a return type like class-string<Foo<A>|Foo<B>> (rightfully, as this is not a valid type) or 'Foo<A>'|'Foo<B>'.

To give some context, I'm trying to map a discriminated union, but the discriminator is on the parent node.

The source looks like this:

{
    "type": "string",
    "node": "..."
}

And the model looks like this:

/** @template T */
interface RootInterface {}

class Root implements RootInterface {
    public function __construct(
        /** @var T */
        NodeInterface $node,
    ){}
}

interface NodeInterface {}
class NodeA implements NodeInterface {}
class NodeB implements NodeInterface {}

Due to the position of the discriminator, I can not directly infer the type of the nested node: I must infer the type of the root node.

It seems that supporting a return type that consists of a union of strings in this case would fix the issue, as I could type the mapper like this:

/** @return 'Root<NodeA>'|'Root<NodeB>' */
fn (string $type) => ...

Here is a full example of my use-case: https://gist.github.com/arnaud-lb/535d89874ed719265f66bc19a88b5fb0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions