Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Type Guard Laravel Package

pinkary-project/type-guard

A lightweight Pinkary package that brings expressive runtime type guards to PHP and Laravel apps, letting you assert and validate value types safely and fail fast with clear errors instead of scattered manual checks.

Deep Wiki
Context7

Getting Started

pinkary-project/type-guard is a runtime assertion helper that also narrows types for static analyzers. It doesn't transform data — it throws when reality doesn't match what you declared, so your code (and PHPStan/Psalm) can stop treating the value as mixed.

Install:

composer require pinkary-project/type-guard

Where to look first: the README's usage example and the package's composer.json autoload.files entry. The helper is registered as a namespaced function (e.g. PinkaryProject\TypeGuard\type_guard()), so it's available as soon as Composer's autoloader runs. Check the exact function name and accepted argument shape before writing code — it's a small package and the API has changed across versions.

First use case — narrowing mixed at a boundary:

use function PinkaryProject\TypeGuard\type_guard;

$payload = json_decode($request->getContent(), true);

$email = type_guard($payload['email'] ?? null, 'string');
// $email is now string for PHPStan/Psalm; throws at runtime otherwise

This is the sweet spot: Request::input(), json_decode(), Cache::get(), Eloquent magic properties, and any mixed return all become safe one line at a time.

Implementation Patterns

Guard at the edges, not everywhere. Call type_guard() where data enters the app (HTTP, queue jobs, webhooks, third-party APIs). Inside your domain you should already have real types (DTOs, value objects); guards there are noise.

final class CreateUserAction
{
    public function __invoke(array $input): User
    {
        return User::create([
            'name'  => type_guard($input['name'] ?? null, 'string'),
            'age'   => type_guard($input['age'] ?? null, 'int'),
            'admin' => type_guard($input['admin'] ?? false, 'bool'),
        ]);
    }
}

Pairs with FormRequests. Keep user-facing rules in the FormRequest; use type_guard for the post-validation shape, especially when you accept array or when data bypasses the request (imports, webhooks, signed callbacks).

Narrowing collections. Because guards narrow the value at the call site, map through them to get a typed array for static analysis:

/** @var array<mixed> $rows */
$ids = array_map(fn ($id) => type_guard($id, 'int'), $rows);
// PHPStan infers array<int>

Class-string / instance narrowing. Where supported, pass a class name to assert an instance and get a narrowed type:

$model = type_guard($value, \App\Models\User::class);
$model->sendWelcomeEmail(); // no more "mixed" complaints

Fail fast in tests. A guard is effectively an assertion. A test that feeds a bad payload throws immediately with a clear message, which beats a downstream "call to member function on null" three stack frames later.

Static analysis integration. Run PHPStan at level 6+ and let guards reduce the mixed surface. This is where the package earns its place: each guard removes a @phpstan-ignore you'd otherwise need. Add guards where PHPStan complains about mixed, not blindly.

Custom guards / extension points. If the package exposes a registration hook (custom closures, custom exception messages), wrap repeated domain checks ("positive int", "UUID string") in your own helper so app code calls one function, not five.

Gotchas and

  • Function autoloading. The helper is a function, not a class. Composer only loads it via autoload.files. If you reference it before vendor/autoload.php is required (some bootstrap scripts, bare test harnesses), you'll get "Call to undefined function." Run composer dump-autoload after installing.
  • Numeric strings vs ints. PHP's type juggling is the classic trap. Confirm in the README (or with a one-line test) whether type_guard('1', 'int') rejects '1'. Most implementations are strict — good — but don't assume; the point of the guard is that it fails loudly.
  • Null is a type. type_guard(null, 'string') should throw. For nullable fields use the union form ('string|null' or an array of types, per the API) rather than ?? '', which hides bugs.
  • Exception type matters. The guard throws — likely TypeError or a package-specific exception. Catch the specific class at your boundary (e.g. render a 422 for a bad webhook payload) rather than a blanket \Throwable.
  • It is not validation. Type guards assert a shape; they don't sanitize, coerce, or produce user-friendly messages. Use Validator/FormRequest for end-user input and guards for internal contracts. Mixing the two surfaces cryptic errors to users.
  • Static analysis only sees what you guard. PHPStan won't infer anything past the guard if you reassign the variable or pass it through another mixed-returning function. Use the return value ($x = type_guard($x, 'int')); don't call the guard for side effects and ignore the result.
  • Performance in hot paths. Scalar checks are negligible; class/union checks inside tight loops (mapping 100k rows) deserve a benchmark. Guard once at the boundary, then trust the type.
  • Don't over-guard. If a signature already declares string, guarding again is redundant. Value lives at mixed boundaries: json_decode, Cache::get, array offsets, DB::select(), and Request::input().
  • Version/API drift. This is a small, young package (~200 stars, active Pinkary ecosystem). Pin the version and read the CHANGELOG on upgrade — function names and signatures can change pre-1.0.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels