Manual
Type Registries
In all the examples so far, we have imported a collection of type constraints into each class:
  package Horse {
    use Moo;
    use Types::Standard qw( Str ArrayRef HashRef Int Any InstanceOf );
    use Types::Common::Numeric qw( PositiveInt );
    use Types::Common::String qw( NonEmptyStr );
    
    has name    => ( is => 'ro', isa => Str );
    has father  => ( is => 'ro', isa => InstanceOf["Horse"] );
    ...;
  }This creates a bunch of subs in the Horse namespace, one for each type. We've used namespace::autoclean to clean these up later.
But it is also possible to avoid pulling all these into the Horse namespace. Instead we'll use a type registry:
  package Horse {
    use Moo;
    use Type::Registry qw( t );
    
    t->add_types('-Standard');
    t->add_types('-Common::String');
    t->add_types('-Common::Numeric');
    
    t->alias_type('InstanceOf["Horse"]' => 'Horsey');
    
    has name     => ( is => 'ro', isa => t('Str') );
    has father   => ( is => 'ro', isa => t('Horsey') );
    has mother   => ( is => 'ro', isa => t('Horsey') );
    has children => ( is => 'ro', isa => t('ArrayRef[Horsey]') );
    ...;
  }
					You don't even need to import the
					
						t()
					
					function. Types::Registry can be used in an entirely object-oriented way.
				
  package Horse {
    use Moo;
    use Type::Registry;
    
    my $reg = Type::Registry->for_me;
    
    $reg->add_types('-Standard');
    $reg->add_types('-Common::String');
    $reg->add_types('-Common::Numeric');
    
    $reg->alias_type('InstanceOf["Horse"]' => 'Horsey');
    
    has name => ( is => 'ro', isa => $reg->lookup('Str') );
    ...;
  }You could create two registries with entirely different definitions for the same named type.
  my $dracula = Aristocrat->new(name => 'Dracula');
  
  package AristocracyTracker {
    use Type::Registry;
    
    my $reg1 = Type::Registry->new;
    $reg1->add_types('-Common::Numeric');
    $reg1->alias_type('PositiveInt' => 'Count');
    
    my $reg2 = Type::Registry->new;
    $reg2->add_types('-Standard');
    $reg2->alias_type('InstanceOf["Aristocrat"]' => 'Count');
    
    $reg1->lookup("Count")->assert_valid("1");
    $reg2->lookup("Count")->assert_valid($dracula);
  }
					Type::Registry uses
					
						AUTOLOAD
					
					, so things like this work:
				
  $reg->ArrayRef->of( $reg->Int );Although you can create as many registries as you like, Type::Registry will create a default registry for each package.
  # Create a new empty registry.
  # 
  my $reg = Type::Registry->new;
  
  # Get the default registry for my package.
  # It will be pre-populated with any types we imported using `use`.
  #
  my $reg = Type::Registry->for_me;
  
  # Get the default registry for some other package.
  #
  my $reg = Type::Registry->for_class("Horse");Type registries are a convenient place to store a bunch of types without polluting your namespace. They are not the same as type libraries though. Types::Standard , Types::Common::String , and Types::Common::Numeric are type libraries; packages that export types for others to use. We will look at how to make one of those later.
For now, here's the best way to think of the difference:
- 
						Type registry
						Curate a collection of types for me to use here in this class. This collection is an implementation detail. 
- 
						Type library
						Export a collection of types to be used across multiple classes. This collection is part of your API. 
Importing Functions
					We've seen how, for instance, Types::Standard exports a sub called
					
						Int
					
					that returns the
					
						Int
					
					type object.
				
  use Types::Standard qw( Int );
  
  my $type = Int;
  $type->check($value) or die $type->get_message($value);Type libraries are also capable of exporting other convenience functions.
					
						
							is_*
						
					
				
				This is a shortcut for checking a value meets a type constraint:
  use Types::Standard qw( is_Int );
  
  if ( is_Int $value ) {
    ...;
  }
					Calling
					
						is_Int($value)
					
					will often be marginally faster than calling
					
						Int->check($value)
					
					because it avoids a method call. (Method calls in Perl end up slower than normal function calls.)
				
					Using things like
					
						is_ArrayRef
					
					in your code might be preferable to
					
						ref($value) eq "ARRAY"
					
					because it's neater, leads to more consistent type checking, and might even be faster. (Type::Tiny can be pretty fast; it is sometimes able to export these functions as XS subs.)
				
					If checking type constraints like
					
						is_ArrayRef
					
					or
					
						is_InstanceOf
					
					, there's no way to give a parameter.
					
						is_ArrayRef[Int]($value)
					
					doesn't work, and neither does
					
						is_ArrayRef(Int, $value)
					
					nor
					
						is_ArrayRef($value, Int)
					
					. For some types like
					
						is_InstanceOf
					
					, this makes them fairly useless; without being able to give a class name, it just acts the same as
					
						is_Object
					
					. See
					"Exporting Parameterized Types"
					for a solution. Also, check out
					isa
					.
				
					There also exists a generic
					
						is
					
					function.
				
  use Types::Standard qw( ArrayRef Int );
  use Type::Utils qw( is );
  
  if ( is ArrayRef[Int], \@numbers ) {
    ...;
  }
					
						
							assert_*
						
					
				
				
					While
					
						is_Int($value)
					
					returns a boolean,
					
						assert_Int($value)
					
					will throw an error if the value does not meet the constraint, and return the value otherwise. So you can do:
				
  my $sum = assert_Int($x) + assert_Int($y);
					And you will get the sum of integers
					
						$x
					
					and
					
						$y
					
					, and an explosion if either of them is not an integer!
				
Assert is useful for quick parameter checks if you are avoiding Type::Params for some strange reason:
  sub add_numbers {
    my $x = assert_Num(shift);
    my $y = assert_Num(shift);
    return $x + $y;
  }
					You can also use a generic
					
						assert
					
					function.
				
  use Type::Utils qw( assert );
  
  sub add_numbers {
    my $x = assert Num, shift;
    my $y = assert Num, shift;
    return $x + $y;
  }
					
						
							to_*
						
					
				
				This is a shortcut for coercion:
  my $truthy = to_Bool($value);It trusts that the coercion has worked okay. You can combine it with an assertion if you want to make sure.
  my $truthy = assert_Bool(to_Bool($value));Shortcuts for exporting functions
This is a little verbose:
  use Types::Standard qw( Bool is_Bool assert_Bool to_Bool );Isn't this a little bit nicer?
  use Types::Standard qw( +Bool );The plus sign tells a type library to export not only the type itself, but all of the convenience functions too.
You can also use:
  use Types::Standard -types;   # export Int, Bool, etc
  use Types::Standard -is;      # export is_Int, is_Bool, etc
  use Types::Standard -assert;  # export assert_Int, assert_Bool, etc
  use Types::Standard -to;      # export to_Bool, etc
  use Types::Standard -all;     # just export everything!!!So if you imagine the functions exported by Types::Standard are like this:
  qw(
    Str             is_Str          assert_Str
    Num             is_Num          assert_Num
    Int             is_Int          assert_Int
    Bool            is_Bool         assert_Bool     to_Bool
    ArrayRef        is_ArrayRef     assert_ArrayRef
  );
  # ... and moreThen "+" exports a horizontal group of those, and "-" exports a vertical group.
Exporting Parameterized Types
It's possible to export parameterizable types like ArrayRef , but it is also possible to export parameterized types.
  use Types::Standard qw( ArrayRef Int );
  use Types::Standard (
    '+ArrayRef' => { of => Int, -as => 'IntList' },
  );
  
  has numbers => (is => 'ro', isa => IntList);
					Using
					
						is_IntList($value)
					
					should be significantly faster than
					
						ArrayRef->of(Int)->check($value)
					
					.
				
					This trick only works for parameterized types that have a single parameter, like
					
						ArrayRef
					
					,
					
						HashRef
					
					,
					
						InstanceOf
					
					, etc. (Sorry,
					
						Dict
					
					and
					
						Tuple
					
					!)
				
Since Type::Tiny 2.8.0 there has been experimental support for a different way of exporting parameterized versions of certain parameterizable type constraints.
  use Types::Standard -types;
  use Types::Standard::ArrayRef (
    IntList         => { of => Int },
    StrList         => { of => Str },
    NonEmptyStrList => { of => Str->where( sub { length($_) > 0 } ) },
    StrNonEmptyList => { of => Str, where => sub { @$_ > 0 } },
    NEStrNEList     => {
      of    => Str->where( sub { length($_) > 0 } ),
      where => sub { @$_ > 0 },
    },
  );
  
  assert_IntList [ 1.. 5 ];                      # doesn't die
  
  is_NonEmptyStrList [ "foo", "bar" ];           # ==> true
  is_NonEmptyStrList [ "foo", "" ];              # ==> false
  is_NonEmptyStrList [];                         # ==> true
  
  is_StrNonEmptyList [ "foo", "bar" ];           # ==> true
  is_StrNonEmptyList [ "foo", "" ];              # ==> true
  is_StrNonEmptyList [];                         # ==> false
  
  is_NEStrNEList [ "foo", "bar" ];               # ==> true
  is_NEStrNEList [ "foo", "" ];                  # ==> false
  is_NEStrNEList [];                             # ==> false
					And of course
					
						where
					
					also accepts a string of Perl code.
				
Lexical imports
Type::Tiny 2.0 combined with Perl 5.37.2+ allows lexically scoped imports. So:
  my $is_ok = do {
    use Types::Standard -lexical, qw( Str ArrayRef );
    ArrayRef->of( Str )->check( \@things );
  };
  
  # The Str and ArrayRef types aren't defined here.Do What I Mean!
  use Type::Utils qw( dwim_type );
  
  my $type = dwim_type("ArrayRef[Int]");
					
						dwim_type
					
					will look up a type constraint from a string and attempt to guess what you meant.
				
					If it's a type constraint that you seem to have imported with
					
						use
					
					, then it should find it. Otherwise, if you're using Moose or Mouse, it'll try asking those. Or if it's in Types::Standard, it'll look there. And if it still has no idea, then it will assume dwim_type("Foo") means dwim_type("InstanceOf['Foo']").
				
It just does a big old bunch of guessing.
					The
					
						is
					
					function will use
					
						dwim_type
					
					if you pass it a string as a type.
				
  use Type::Utils qw( is );
  
  if ( is "ArrayRef[Int]", \@numbers ) {
    ...;
  }Types::Common
Notice that in a lot of examples we're importing one or two functions each from a few different modules:
  use Types::Common::Numeric qw( PositiveInt );
  use Types::Common::String qw( NonEmptyStr );
  use Types::Standard qw( ArrayRef Slurpy );
  use Type::Params qw( signature_for );A module called Types::Common exists which acts as a single place you can use for importing most of Type::Tiny's commonly used types and functions.
  use Types::Common qw(
    PositiveInt NonEmptyStr ArrayRef Slurpy
    signature_for
  );Types::Common provides:
- All the types from Types::Standard .
- All the types from Types::Common::Numeric and Types::Common::String .
- All the types from Types::TypeTiny .
- 
						The
						-sigstag from Type::Params .
- 
						The
						t()function from Type::Registry .
Next Steps
You now know pretty much everything there is to know about how to use type libraries.
Here's your next step:
- 
						Type::Tiny::Manual::Libraries
						Defining your own type libraries, including extending existing libraries, defining new types, adding coercions, defining parameterizable types, and the declarative style.