profile
viewpoint
If you are wondering where the data of this site comes from, please visit https://api.github.com/users/scotttrinh/events. GitMemory does not store any data, but only uses NGINX to cache data for a period of time. The idea behind GitMemory is simply to give users a better reading experience.
Scott Trinh scotttrinh @ca-la New York City

colinhacks/zod 4084

TypeScript-first schema validation with static type inference

org-rs/org-rs 675

org-mode parser rewrite in Rust

scotttrinh/angular-localForage 665

Angular service & directive for https://github.com/mozilla/localForage (Offline storage, improved.)

ca-la/remote-data 4

An algebraic data type representing the states of getting remote data

AwkwardAlliance/halfseven 3

D&D Management Application

ca-la/remote-collection 3

A RemoteData Collection class

kdl-org/kdl-org.github.io 2

Here's where kdl.dev is hosted from.

scotttrinh/angular-date-range-picker 1

Pure Angular date range picker, no jQuery

ca-la/koa-middleware 0

CALA Common Koa Middleware

scotttrinh/angular-bootstrap-colorpicker 0

Native AngularJS colorpicker directive. No dependency on jQuery or jQuery plugin is required.

push eventscotttrinh/dotfiles

Scott Trinh

commit sha d4f30d452097a327d4406cd073eed6f65c622f52

Add git module and configuration

view details

push time in 14 hours

push eventscotttrinh/dotfiles

Scott Trinh

commit sha 51e2adc7be3101d0ec9ed80c0a36a7898db0db1e

Move Homebrew config to separate module

view details

push time in 14 hours

push eventscotttrinh/dotfiles

Scott Trinh

commit sha 9d2be0716f128a95663d5b29f05273cb720543ff

Add homebrew integration for non-nix packages

view details

Scott Trinh

commit sha 46eb83f69aabfc5ba2f215063f7933c426ff4346

Remove emacs from silliconOverlay

view details

push time in 14 hours

push eventscotttrinh/dotfiles

Scott Trinh

commit sha f8913854514a9515be36e19322a6f6f104d797cc

A little cleanup

view details

push time in 15 hours

push eventscotttrinh/dotfiles

Scott Trinh

commit sha e5028551803b8abdb3c4755f60317042666acc64

Move most emacs config to separate module

view details

push time in 16 hours

create barnchscotttrinh/dotfiles

branch : main

created branch time in 2 days

created repositoryscotttrinh/dotfiles

Nix configuration

created time in 2 days

issue commentcolinhacks/zod

`refine` doesn't throw an error until `password` field validation passed

Yeah, this is expected behavior in v3. The refinement (and other "effects" like transformation) happen after the parsing, and the parsing will halt the whole pipeline if it encounters errors in the parsing step.

For more details on the motivation behind this part of the refactor, see #264

jorisre

comment created time in 2 days

delete branch scotttrinh/emacs

delete branch : bump-macos-110502

delete time in 2 days

pull request commentcmacrae/emacs

Bump maximum allowed macOS version

@cmacrae

Thanks for the detailed answer. I'm still trying to wrap my head around how nix works, and that really helped connect some dots for me! I've had a hard time looking at complex multi-file configs like yours (and @montchr) and really understand what's happening, so having this extra bit of explanation is super helpful. 🙏

scotttrinh

comment created time in 2 days

issue commentcolinhacks/zod

z.enum for as const numbers?

This has come up before, but z.enum is for creating an enum-like thing for strings. Gives you a runtime representation that you can use like a TypeScript enum, but the type is a union of string literals. If you just want a union of number literals, you can use z.union.

See https://github.com/colinhacks/zod/issues/626

CodeSandbox

const OrderEnum = z.union([z.literal(1), z.literal(2), z.literal(3)]);
mmahalwy

comment created time in 2 days

startedhlissner/doom-emacs

started time in 2 days

startedhlissner/dotfiles

started time in 2 days

PR closed cmacrae/emacs

Bump maximum allowed macOS version

(Sorry for the empty description here, opened PR from the Github VSCode thing)

Trying to get this working on my new M1 laptop that has macOS 11.5.2, and while trying to debug the error I'm seeing I noticed this line. Not sure if it actually fixes my issue yet, but thought I'd fork and open a PR anyway. Will report back if it makes any difference!

+1 -1

2 comments

1 changed file

scotttrinh

pr closed time in 2 days

pull request commentcmacrae/emacs

Bump maximum allowed macOS version

Was not required at all. For some reason, having the emacs-overlay at the same time was the issue. Adding it produces this error:

error: 'builtins.storePath' is not allowed in pure evaluation mode

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:335:15:

          334|     let
          335|       path' = builtins.storePath path;
             |               ^
          336|       res =
(use '--show-trace' to show detailed location information)

With the trace:

<details> <summary>With the trace</summary>

error: 'builtins.storePath' is not allowed in pure evaluation mode

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:335:15:

          334|     let
          335|       path' = builtins.storePath path;
             |               ^
          336|       res =

       … while evaluating the attribute 'passAsFile'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/pkgs/build-support/buildenv/default.nix:77:5:

           76|     # XXX: The size is somewhat arbitrary
           77|     passAsFile = if builtins.stringLength pkgs >= 128*1024 then [ "pkgs" ] else [ ];
             |     ^
           78|   }

       … while evaluating the attribute 'passAsFile' of the derivation 'home-manager-fonts'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/pkgs/stdenv/generic/make-derivation.nix:207:7:

          206|         let
          207|           # Indicate the host platform of the derivation if cross compiling.
             |       ^
          208|           # Fixed-output derivations like source tarballs shouldn't get a host

       … while evaluating the attribute 'value'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:392:44:

          391|       defnsByName' = byName "config" (module: value:
          392|           [{ inherit (module) file; inherit value; }]
             |                                            ^
          393|         ) configs;

       … while evaluating 'dischargeProperties'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:609:25:

          608|   */
          609|   dischargeProperties = def:
             |                         ^
          610|     if def._type or "" == "merge" then

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:538:137:

          537|         defs' = concatMap (m:
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
             |                                                                                                                                         ^
          539|         ) defs;

       … while evaluating definitions from `/nix/store/qw8igmbp09dz45k7a1b4w2ynz1gr2p6y-source/modules/targets/darwin/fonts.nix':

       … while evaluating anonymous lambda

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:537:28:

          536|         # Process mkMerge and mkIf properties.
          537|         defs' = concatMap (m:
             |                            ^
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:537:17:

          536|         # Process mkMerge and mkIf properties.
          537|         defs' = concatMap (m:
             |                 ^
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … while evaluating the attribute 'values'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:650:7:

          649|     in {
          650|       values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
             |       ^
          651|       inherit highestPrio;

       … while evaluating the attribute 'values'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:551:9:

          550|       in {
          551|         values = defs''';
             |         ^
          552|         inherit (defs'') highestPrio;

       … while evaluating the attribute 'mergedValue'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:557:5:

          556|     # Type-check the remaining definitions, and merge them. Or throw if no definitions.
          557|     mergedValue =
             |     ^
          558|       if isDefined then

       … while evaluating the option `home-manager.users.scotttrinh.home.activation.copyFonts.data':

       … while evaluating the attribute 'value'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:525:9:

          524|     in warnDeprecation opt //
          525|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          526|         inherit (res.defsFinal') highestPrio;

       … while evaluating anonymous lambda

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:140:72:

          139|           # For definitions that have an associated option
          140|           declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
             |                                                                        ^
          141|

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:304:20:

          303|               then recurse (path ++ [name]) value
          304|               else f (path ++ [name]) value;
             |                    ^
          305|         in mapAttrs g set;

       … while evaluating 'g'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:301:19:

          300|           g =
          301|             name: value:
             |                   ^
          302|             if isAttrs value && cond value

       … from call site

       … while evaluating the attribute 'data'

       at /nix/store/qw8igmbp09dz45k7a1b4w2ynz1gr2p6y-source/modules/lib/dag.nix:85:9:

           84|         name = n;
           85|         data = v.data;
             |         ^
           86|         after = v.after ++ dagBefore dag n;

       … while evaluating the attribute 'data'

       at /nix/store/qw8igmbp09dz45k7a1b4w2ynz1gr2p6y-source/modules/lib/dag.nix:91:37:

           90|     in if sorted ? result then {
           91|       result = map (v: { inherit (v) name data; }) sorted.result;
             |                                     ^
           92|     } else

       … while evaluating 'mkCmd'

       at /nix/store/qw8igmbp09dz45k7a1b4w2ynz1gr2p6y-source/modules/home-environment.nix:559:17:

          558|       let
          559|         mkCmd = res: ''
             |                 ^
          560|             noteEcho Activating ${res.name}

       … from call site

       … while evaluating the attribute 'text' of the derivation 'activation-script'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/pkgs/stdenv/generic/make-derivation.nix:207:7:

          206|         let
          207|           # Indicate the host platform of the derivation if cross compiling.
             |       ^
          208|           # Fixed-output derivations like source tarballs shouldn't get a host

       … while evaluating the attribute 'buildCommand' of the derivation 'home-manager-generation'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/pkgs/stdenv/generic/make-derivation.nix:207:7:

          206|         let
          207|           # Indicate the host platform of the derivation if cross compiling.
             |       ^
          208|           # Fixed-output derivations like source tarballs shouldn't get a host

       … while evaluating the attribute 'text' of the derivation 'activation-scotttrinh'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/pkgs/stdenv/generic/make-derivation.nix:207:7:

          206|         let
          207|           # Indicate the host platform of the derivation if cross compiling.
             |       ^
          208|           # Fixed-output derivations like source tarballs shouldn't get a host

       … while evaluating anonymous lambda

       at /nix/store/qw8igmbp09dz45k7a1b4w2ynz1gr2p6y-source/nix-darwin/default.nix:125:56:

          124|     system.activationScripts.postActivation.text =
          125|       concatStringsSep "\n" (mapAttrsToList (username: usercfg: ''
             |                                                        ^
          126|         echo Activating home-manager configuration for ${username}

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:259:16:

          258|   mapAttrsToList = f: attrs:
          259|     map (name: f name attrs.${name}) (attrNames attrs);
             |                ^
          260|

       … while evaluating anonymous lambda

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:259:10:

          258|   mapAttrsToList = f: attrs:
          259|     map (name: f name attrs.${name}) (attrNames attrs);
             |          ^
          260|

       … from call site

       … while evaluating the attribute 'value'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:392:44:

          391|       defnsByName' = byName "config" (module: value:
          392|           [{ inherit (module) file; inherit value; }]
             |                                            ^
          393|         ) configs;

       … while evaluating 'dischargeProperties'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:609:25:

          608|   */
          609|   dischargeProperties = def:
             |                         ^
          610|     if def._type or "" == "merge" then

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:538:137:

          537|         defs' = concatMap (m:
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
             |                                                                                                                                         ^
          539|         ) defs;

       … while evaluating definitions from `<unknown-file>':

       … while evaluating anonymous lambda

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:537:28:

          536|         # Process mkMerge and mkIf properties.
          537|         defs' = concatMap (m:
             |                            ^
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:537:17:

          536|         # Process mkMerge and mkIf properties.
          537|         defs' = concatMap (m:
             |                 ^
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … while evaluating the attribute 'values'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:650:7:

          649|     in {
          650|       values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
             |       ^
          651|       inherit highestPrio;

       … while evaluating the attribute 'values'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:551:9:

          550|       in {
          551|         values = defs''';
             |         ^
          552|         inherit (defs'') highestPrio;

       … while evaluating the attribute 'mergedValue'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:557:5:

          556|     # Type-check the remaining definitions, and merge them. Or throw if no definitions.
          557|     mergedValue =
             |     ^
          558|       if isDefined then

       … while evaluating the option `system.activationScripts.postActivation.text':

       … while evaluating the attribute 'value'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:525:9:

          524|     in warnDeprecation opt //
          525|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          526|         inherit (res.defsFinal') highestPrio;

       … while evaluating anonymous lambda

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:140:72:

          139|           # For definitions that have an associated option
          140|           declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
             |                                                                        ^
          141|

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:304:20:

          303|               then recurse (path ++ [name]) value
          304|               else f (path ++ [name]) value;
             |                    ^
          305|         in mapAttrs g set;

       … while evaluating 'g'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:301:19:

          300|           g =
          301|             name: value:
             |                   ^
          302|             if isAttrs value && cond value

       … from call site

       … while evaluating the attribute 'value'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:392:44:

          391|       defnsByName' = byName "config" (module: value:
          392|           [{ inherit (module) file; inherit value; }]
             |                                            ^
          393|         ) configs;

       … while evaluating 'dischargeProperties'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:609:25:

          608|   */
          609|   dischargeProperties = def:
             |                         ^
          610|     if def._type or "" == "merge" then

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:538:137:

          537|         defs' = concatMap (m:
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))
             |                                                                                                                                         ^
          539|         ) defs;

       … while evaluating definitions from `/nix/store/nb2kapr1yf12ra2x3jmdbm2lwfh9c1pr-source/modules/system/activation-scripts.nix':

       … while evaluating anonymous lambda

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:537:28:

          536|         # Process mkMerge and mkIf properties.
          537|         defs' = concatMap (m:
             |                            ^
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:537:17:

          536|         # Process mkMerge and mkIf properties.
          537|         defs' = concatMap (m:
             |                 ^
          538|           map (value: { inherit (m) file; inherit value; }) (builtins.addErrorContext "while evaluating definitions from `${m.file}':" (dischargeProperties m.value))

       … while evaluating the attribute 'values'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:650:7:

          649|     in {
          650|       values = concatMap (def: if getPrio def == highestPrio then [(strip def)] else []) defs;
             |       ^
          651|       inherit highestPrio;

       … while evaluating the attribute 'values'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:551:9:

          550|       in {
          551|         values = defs''';
             |         ^
          552|         inherit (defs'') highestPrio;

       … while evaluating the attribute 'mergedValue'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:557:5:

          556|     # Type-check the remaining definitions, and merge them. Or throw if no definitions.
          557|     mergedValue =
             |     ^
          558|       if isDefined then

       … while evaluating the option `system.activationScripts.script.text':

       … while evaluating the attribute 'value'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:525:9:

          524|     in warnDeprecation opt //
          525|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          526|         inherit (res.defsFinal') highestPrio;

       … while evaluating anonymous lambda

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/modules.nix:140:72:

          139|           # For definitions that have an associated option
          140|           declaredConfig = mapAttrsRecursiveCond (v: ! isOption v) (_: v: v.value) options;
             |                                                                        ^
          141|

       … from call site

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:304:20:

          303|               then recurse (path ++ [name]) value
          304|               else f (path ++ [name]) value;
             |                    ^
          305|         in mapAttrs g set;

       … while evaluating 'g'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/lib/attrsets.nix:301:19:

          300|           g =
          301|             name: value:
             |                   ^
          302|             if isAttrs value && cond value

       … from call site

       … while evaluating the attribute 'activationScript' of the derivation 'darwin-system-21.11.20210916.cbb9567+darwin4.007d700'

       at /nix/store/p6cjkwimwlkd4nyfckmx884gh0vnksas-source/pkgs/stdenv/generic/make-derivation.nix:207:7:

          206|         let
          207|           # Indicate the host platform of the derivation if cross compiling.
             |       ^
          208|           # Fixed-output derivations like source tarballs shouldn't get a host

</details>

scotttrinh

comment created time in 2 days

issue closedcolinhacks/zod

Best practices: Use schema validation along classes

Hello,

This issue is not related to a Zod problem, but I'm sure people using the lib can help me <3

This is a simple Schema (we have to imagine it is more complex):

export const PersonSchema = z.object({
    id: z.string(),
    firstname: z.string(),
    lastname: z.string()
});

export type PersonType = z.infer<typeof PersonSchema>;

On server side, when I get a POST request, I can validate the payload using:

const newPerson = PersonSchema.parse(payload);

Great, my noSQL database will stay clean !

But now, I want to use this on client-side. So I use the same method.

const newPerson = PersonSchema.parse(payload);

My front get a Person object now, but to display it, I would like to use a class method like this for example:

newPerson.getFullName();

But newPerson is not a class instance...

So far, I found those solutions:

Solution 1:

Create a class Person:

class PersonClass implements PersonType {
    id: ZodString['_output'];
    lastname: ZodString['_output'];
    firstName: ZodString['_output'];

    constructor(newPerson: PersonType) {
        this.id = newPerson.contactEmail;
        this.lastname = newPerson.lastname;
        this.firstname = newPerson.firstname;
    }

    getFullName() {
        return this.firstname + " "  + this.lastname;
    }

OR

class PersonClass implements PersonType {
    id: z.infer<typeof PersonSchema.shape.name>;
    lastname: z.infer<typeof PersonSchema.shape.name>;
    firstName: z.infer<typeof PersonSchema.shape.name>;

    constructor(newPerson: PersonType) {
        this.id = newPerson.contactEmail;
        this.lastname = newPerson.lastname;
        this.firstname = newPerson.firstname;
    }
    
    getFullName() {
        return this.firstname + " "  + this.lastname;
    }
}

I found this on the same subject:

https://github.com/colinhacks/zod/issues/38

But the more Person will have attributes, the more the class size is also growing. And I will have to parse my object, then to make an instance of the class...

Solution 2:

I don't use classes, and I create a getFullName() methods like this:

const getFullName = (person: PersonType) => {return person.firstname + " " + person.lastname;}

So my question is:

How and when do you use Zod in your projects ?

Only to validate payloads ? How to use methods on parsed objects?

closed time in 3 days

X-Titouan

issue commentcolinhacks/zod

Best practices: Use schema validation along classes

Closing, but feel free to add any additional thoughts here. If we want this to be an ongoing discussion point, we can also migrate this to a GitHub discussion.

X-Titouan

comment created time in 3 days

create barnchscotttrinh/emacs

branch : bump-macos-110502

created branch time in 3 days

PR opened cmacrae/emacs

Bump maximum allowed macOS version
+1 -1

0 comment

1 changed file

pr created time in 3 days

fork scotttrinh/emacs

Nightly custom Emacs builds for macOS Nix environments

fork in 3 days

startedcmacrae/config

started time in 3 days

issue commentcolinhacks/zod

Best practices: Use schema validation along classes

Yeah, I wouldn't think that you'd want the function itself in the schema since the schema is really just about validating data. And, as you've seen, you cannot implement the function within the schema unless you made it lazy, but then you'd end up having to write the type out manually.

I don't often write class-based code, so I don't think I'm in a great position to help you out here, so I'll let someone else chime in here. I imagine that most class based code uses validation as part of the constructor, but I don't know how you avoid having to redeclare all of the types as you've pointed out.

Another option is to use modules as a class-like structure. This is more similar to what I often do in practice and has a similar feel to class-based solutions.

CodeSandbox

// Person.ts
import { z } from "zod";

const person = z.object({
  id: z.string(),
  firstName: z.string(),
  lastName: z.string()
});
export type Person = z.infer<typeof person>;

export function create(data: unknown) {
  return {
    ...person.parse(data),
    getFullName: function (this: Person) {
      return `${this.firstName} ${this.lastName}`;
    }
  };
}
// index.ts
import test from "tape";
import * as Person from "./Person";

test("valid", (t) => {
  const valid = Person.create({
    id: "abc",
    firstName: "Scott",
    lastName: "Trinh"
  });

  t.equal(valid.getFullName(), "Scott Trinh");
  t.end();
});
X-Titouan

comment created time in 4 days

startedvic/vix

started time in 4 days

Pull request review commentcolinhacks/zod

fix typos

 export class ZodEffects<   constructor(def: ZodEffectsDef<T>) {     super(def);     // if (def.schema instanceof ZodEffects) {-    //   throw new Error(ZodFirstPartyTypeKind.ZodEffectscannot be nested.");+    //   throw new Error(ZodFirstPartyTypeKind.ZodEffects cannot be nested.");

Not a huge deal, just makes doing a git blame on this chunk of commented out code have a random typo fix commit in the middle of it. Definitely not an actual problem 😅

frankie303

comment created time in 9 days

PullRequestReviewEvent

issue commentcolinhacks/zod

.optional() and --exactOptionalPropertyTypes

I wonder if we can introduce this under a separate method like exactOptional? Or maybe have optional take a configuration parameter. If we go the config route, I'd want to get some direction from @colinhacks since there has been talks about using arguments to do things like custom error messages, etc, so we probably want to coordinate a bit.

bwbuchanan

comment created time in 9 days

Pull request review commentcolinhacks/zod

fix typos

 export class ZodEffects<   constructor(def: ZodEffectsDef<T>) {     super(def);     // if (def.schema instanceof ZodEffects) {-    //   throw new Error(ZodFirstPartyTypeKind.ZodEffectscannot be nested.");+    //   throw new Error(ZodFirstPartyTypeKind.ZodEffects cannot be nested.");

Can you revert this one? It's actually invalid even with the typo fixed, so no reason to add more git history to this line.

frankie303

comment created time in 9 days

PullRequestReviewEvent
PullRequestReviewEvent

issue commentcolinhacks/zod

Best practices: Use schema validation along classes

Definitely a matter of taste here, but I find a functional style and using POJOs (Plain old JavaScript Objects) is more idiomatic with JavaScript than this more traditional OO style, especially since JavaScript classes are not classical-OO classes, since they're syntactic sugar over regular JS functions/prototypes. If classes aren't strictly necessary, you can attach functions directly to any plain object, also:

CodeSandbox

const person = z.object({
  id: z.string(),
  firstName: z.string(),
  lastName: z.string()
});
type Person = z.infer<typeof person>;

const valid = {
  ...person.parse({
    id: "abc",
    firstName: "Scott",
    lastName: "Trinh"
  }),
  getFullName: function (this: Person) {
    return `${this.firstName} ${this.lastName}`;
  }
};
valid.getFullName(); // "Scott Trinh"
X-Titouan

comment created time in 9 days