marcin-orlowski/type-asserts
A lightweight PHP library of type assertion helpers for Laravel and standalone projects, letting you validate values against expected types with simple, readable calls and clear failures.
Install it:
composer require marcin-orlowski/type-asserts
Read these first, in this order:
README.md for the supported assertion surfacesrc/TypeAsserts.php (or the namespace root) for the exact method names and whether assertions return the value or voidsrc/Exceptions/ for the exception type your try/catch blocks will need to handleFirst use case: assert types at a service boundary, not in every controller. A typical first integration is validating a raw input value before it enters typed domain code:
use MarcinOrlowski\TypeAsserts\TypeAsserts;
final class CancelOrder
{
public function __invoke(mixed $orderId): void
{
$orderId = TypeAsserts::assertInt($orderId, 'orderId');
// $orderId is now safe to pass into a typed constructor
}
}
Alias the class if the static call feels verbose:
use MarcinOrlowski\TypeAsserts\TypeAsserts as Assert;
$id = Assert::assertInt($id);
Laravel does not auto-discover anything here — there is no service provider and nothing to publish. It is a plain static helper library.
Service-layer guards. The strongest day-to-day pattern is to treat this as a lightweight runtime contract at the edge of typed code: HTTP input, queue payloads, config values, and array data coming from the database or external APIs. Laravel’s validator is still the right tool for user-facing form errors; type asserts are for places where a wrong type is a programmer error or an upstream contract violation.
DTO / value object constructors. Assert in constructors so invalid state can’t be instantiated:
final class Money
{
public function __construct(public readonly int $amount, public readonly string $currency)
{
TypeAsserts::assertInt($amount, 'amount');
TypeAsserts::assertString($currency, 'currency');
}
}
Config and environment checks. Assert config values in a service provider’s boot() or register() so a bad .env fails at boot rather than halfway through a request:
TypeAsserts::assertInt(config('services.billing.timeout'));
Queue and console payloads. Jobs often deserialize arrays with no type guarantees. Assert required keys and types at the top of handle() before dispatching to domain code.
Instance checks for interfaces. Use the instance-of assertion for collaborators passed through generic containers or plugin-style registries where PHP’s type system has been erased by array or mixed.
Translate to Laravel exceptions at the boundary. Wrap assertions in a small helper that converts the package’s exception into ValidationException or an HTTP 422 response for API endpoints, and let it bubble up as a 500 everywhere else (because it indicates a code bug, not user input error).
Return-value usage. If assertions return the checked value, use the return value rather than reusing the original variable — this keeps the asserted type visible to static analysers:
$id = TypeAsserts::assertInt($request->input('id'));
Testing. Assertions are cheap and static, so test the happy path and use expectException() against the package’s exception class for the failure path. This is often faster and clearer than testing through a full request.
assertInt() looks like PHPUnit’s assertIsInt() and native assert(). In test files, alias the class to avoid confusion.void before chaining or assigning; versions of small utility packages change this.src/Exceptions/. If it extends \InvalidArgumentException, catching that is a safe fallback, but catch the concrete class for clarity.assertInt('123') passes — and if it does, do not rely on that behaviour staying stable.assertNullable* helpers or via a flag/second argument. Read the class; guessing wrong here is a common source of production surprises.TypeGuard class if you need to swap or stub them in tests.composer.json, and be prepared to inline the handful of static methods into a Support/Assert.php trait if it becomes incompatible with a future PHP minor. The logic is trivial enough that vendor-copying is a realistic exit plan.declare(strict_types=1); in files that call these assertions. The library enforces runtime types, but strict types make your own surrounding code predictable too.final and static, so don’t plan to subclass it. Compose around it: a thin project-local assertion helper gives you one place to change behaviour, add logging, or migrate away later.How can I help you explore Laravel packages today?