@@ -753,6 +753,128 @@ Features:
753753- Preserves original casing
754754- Handles edge cases like unchanged plurals (sheep→sheep)
755755
756+ ### Branded Types (TypeScript)
757+
758+ Nano-string-utils provides branded types for compile-time type safety with validated strings. These types add zero runtime overhead and are fully tree-shakeable.
759+
760+ ``` typescript
761+ import { branded } from " nano-string-utils" ;
762+ ```
763+
764+ #### Type Guards
765+
766+ Type guards narrow string types to branded types:
767+
768+ ``` typescript
769+ const input: string = getUserInput ();
770+
771+ if (branded .isValidEmail (input )) {
772+ // input is now typed as Email
773+ sendEmail (input );
774+ }
775+
776+ if (branded .isValidUrl (input )) {
777+ // input is now typed as URL
778+ fetch (input );
779+ }
780+
781+ if (branded .isSlug (input )) {
782+ // input is now typed as Slug
783+ useAsRoute (input );
784+ }
785+ ```
786+
787+ #### Builder Functions
788+
789+ Safely create branded types with validation:
790+
791+ ``` typescript
792+ // Returns Email | null
793+ const email
= branded .
toEmail (
" [email protected] " );
794+ if (email ) {
795+ sendEmail (email ); // email is typed as Email
796+ }
797+
798+ // Returns URL | null
799+ const url = branded .toUrl (" https://example.com" );
800+ if (url ) {
801+ fetch (url ); // url is typed as URL
802+ }
803+
804+ // Always returns Slug (transforms input)
805+ const slug = branded .toSlug (" Hello World!" ); // 'hello-world' as Slug
806+ createRoute (slug );
807+
808+ // Smart slug handling
809+ const slug2 = branded .ensureSlug (" already-a-slug" ); // returns as-is if valid
810+ const slug3 = branded .ensureSlug (" Not A Slug!" ); // transforms to 'not-a-slug'
811+ ```
812+
813+ #### Assertion Functions
814+
815+ Assert types with runtime validation:
816+
817+ ``` typescript
818+ const input: string = getUserInput ();
819+
820+ // Throws BrandedTypeError if invalid
821+ branded .assertEmail (input );
822+ // input is now typed as Email
823+ sendEmail (input );
824+
825+ // Custom error messages
826+ branded .assertUrl (input , " Invalid webhook URL" );
827+
828+ // All assertion functions available
829+ branded .assertEmail (str );
830+ branded .assertUrl (str );
831+ branded .assertSlug (str );
832+ ```
833+
834+ #### Unsafe Variants
835+
836+ For trusted inputs where validation isn't needed:
837+
838+ ``` typescript
839+ // Use only when you're certain the input is valid
840+ const trustedEmail
= branded .
unsafeEmail (
" [email protected] " );
841+ const trustedUrl = branded .unsafeUrl (" https://internal.api" );
842+ const trustedSlug = branded .unsafeSlug (" already-valid-slug" );
843+ ```
844+
845+ #### Available Types
846+
847+ - ` Email ` - Validated email addresses
848+ - ` URL ` - Validated URLs (http/https/ftp/ftps)
849+ - ` Slug ` - URL-safe slugs (lowercase, hyphenated)
850+ - ` Brand<T, K> ` - Generic branding utility for custom types
851+
852+ #### Benefits
853+
854+ - ** Zero runtime overhead** - Types are erased at compilation
855+ - ** Type safety** - Prevent passing unvalidated strings to functions
856+ - ** IntelliSense support** - Full autocomplete and type hints
857+ - ** Tree-shakeable** - Only imported if used
858+ - ** Composable** - Works with existing string functions
859+
860+ ``` typescript
861+ // Example: Type-safe API
862+ function sendNewsletter(email : branded .Email ) {
863+ // Can only be called with validated emails
864+ api .send (email );
865+ }
866+
867+ // Won't compile without validation
868+ const userInput
= " [email protected] " ;
869+ // sendNewsletter(userInput); // ❌ Type error!
870+
871+ // Must validate first
872+ const validated = branded .toEmail (userInput );
873+ if (validated ) {
874+ sendNewsletter (validated ); // ✅ Type safe!
875+ }
876+ ```
877+
756878## Bundle Size
757879
758880Each utility is optimized to be as small as possible:
0 commit comments