tomred has asked for the wisdom of the Perl Monks concerning the following question:
I have the following Type defined.
package Types; use v5.34; use warnings; use Type::Utils qw( as coerce declare from via ); use Types::Common qw( Enum Str ); use Type::Library -base, -declare => qw( CreditType InvoiceType ); declare InvoiceType, as Enum [qw/ ACCPAY ACCREC /]; coerce InvoiceType, from Str, via { #warn "Trying to coerce $_\n"; my %types = ( Invoice => 'ACCREC', SupplierInvoice => 'ACCPAY', ); #my $ret = $types{$_}; #warn "Returning $ret\n"; return $types{$_}; } ; declare CreditType, as Enum [qw/ ACCPAYCREDIT ACCRECCREDIT /]; coerce CreditType, from Str, via { warn "Trying to coerce $_\n"; my %types = ( Credit => 'ACCRECCREDIT', SupplierCredit => 'ACCPAYCREDIT', ); my $ret = $types{$_}; warn "Returning $ret\n"; return $types{$_}; } ; 1;
I have a class that uses the types as a union, this or that
package MyApp; use v5.34; use warnings; use Moo; use Types qw/ InvoiceType CreditType /; has 'type' => ( is => 'ro', isa => InvoiceType | CreditType, required => 1, coerce => 1, ); sub run { my ($self) = @_; say "Running with ".$self->type; } 1;
I have a test to make sure it's doing what I expect `t/type.t`
#!/opt/perl5/bin/perl use v5.34; use warnings; use Test::More; use Types qw( InvoiceType CreditType ); { subtest 'Type coercion' => sub { is InvoiceType->coerce('Invoice'), 'ACCREC', 'Can coerce a sales invoice'; is InvoiceType->coerce('SupplierInvoice'), 'ACCPAY', 'Can coerce a supplier invoice'; is CreditType->coerce('Credit'), 'ACCRECCREDIT', 'Can coerce a credit type'; is CreditType->coerce('SupplierCredit'), 'ACCPAYCREDIT', 'Can coerce a supplier credit type'; }; } { my $class = 'MyApp'; use_ok($class); subtest 'Class coercion' => sub { for my $t ( qw/Invoice SupplierInvoice Credit SupplierCredit / + ) { note "Type=$t"; my $x = new_ok($class => [ type => $t ]); note "Now Type=".$x->type; } }; } done_testing;
t/type.t .. # Subtest: Type coercion ok 1 - Can coerce a sales invoice ok 2 - Can coerce a supplier invoice ok 3 - Can coerce a credit type ok 4 - Can coerce a supplier credit type 1..4 ok 1 - Type coercion ok 2 - use MyApp; # Subtest: Class coercion # Type=Invoice ok 1 - An object of class 'MyApp' isa 'MyApp' # Type=SupplierInvoice ok 2 - An object of class 'MyApp' isa 'MyApp' # Type=Credit not ok 3 - MyApp->new() died # Failed test 'MyApp->new() died' # at t/type.t line 31. # Error was: Undef did not pass type constraint "InvoiceType| +CreditType" (in $args->{"type"}) at /home/dpaikkos/spl/local/lib/perl +5/Test/More.pm line 741 # "InvoiceType|CreditType" requires that the value pass "Credi +tType" or "InvoiceType" # Undef did not pass type constraint "InvoiceType" # "InvoiceType" is a subtype of "Enum["ACCPAY","ACCREC"]" # "Enum["ACCPAY","ACCREC"]" requires that the value is def +ined # Undef did not pass type constraint "CreditType"
I excel at leaving typos in my code but I am pretty sure there are none in the code so far. The coercions appear to work in a stand alone fashion but when used as a union, the 2nd Type does not appear to apply the coercion. If I swap the "CreditType" to be the first item, I find that the InvoiceType fails.
I suspect I could use some kind of named parameterized coercion and `plus_coercions` but I hit this snag and haven't been able to move forward.
Does anyone have any insights into what I'm doing wrong?
Thanks in advance
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Type coercion and union
by tomred (Sexton) on Mar 10, 2026 at 13:54 UTC | |
|
Re: Type coercion and union
by tobyink (Canon) on Mar 25, 2026 at 15:47 UTC |