mkOptionType explanation

I am a bit confused about mkOptionType. Ok, I get that it is used to define custom types for the NixOS DSL. I’d like to understand how that works in the case of simple-nixos-mailserver / nixos-mailserver · GitLab.

I can see:

  loginAccount = mkOptionType {
          name = "Login Account";
   };

or to give you some context

loginAccounts = mkOption {
      type = types.attrsOf (types.submodule ({ name, ... }: {
        options = {
          name = mkOption {
            type = types.str;
            example = "user1@example.com";
            description = "Username";
          };
[...]

   extraVirtualAliases = mkOption {
      type = let
        loginAccount = mkOptionType {
          name = "Login Account";
          check = (account: builtins.elem account (builtins.attrNames cfg.loginAccounts));
        };
      in with types; attrsOf (either loginAccount (nonEmptyListOf loginAccount));
      example = {
        "info@example.com" = "user1@example.com";
        "postmaster@example.com" = "user1@example.com";
        "abuse@example.com" = "user1@example.com";
        "multi@example.com" = [ "user1@example.com" "user2@example.com" ];
      };
      description = ''
        Virtual Aliases. A virtual alias `"info@example.com" = "user1@example.com"` means that
        all mail to `info@example.com` is forwarded to `user1@example.com`. Note
        that it is expected that `postmaster@example.com` and `abuse@example.com` is
        forwarded to some valid email address. (Alternatively you can create login
        accounts for `postmaster` and (or) `abuse`). Furthermore, it also allows
        the user `user1@example.com` to send emails as `info@example.com`.
        It's also possible to create an alias for multiple accounts. In this
        example all mails for `multi@example.com` will be forwarded to both
        `user1@example.com` and `user2@example.com`.
      '';
      default = {};
    };

where is this type Login Account used at all? I mean there is some loginAccounts but how does that fit together?

Specifically loginAccount type is defined with let expression inside of extraVirtualAliases. So how can a member of attrset loginAccounts be of type loginAccount or as a matter of fact how is a value of type loginAccount even constructed? I was grepping through the code and can’t find any other mention of loginAccount*.

Here we have the check attribute, which holds a predicate.

Each value that you can pass into this predicate and that will then return true is a valid value of the type loginAccount.

Thanks for explanation. Thought this check was just for validation purposes.

You could do check = lib.const true and then everything that exists is of type loginAccount? I thought you’d need some type constructor to construct an instance (ala LoginAccount "some@email"). But yeah, I’m probably overcomplicating since I was reading a book about Haskell.