dynamodb-onetable: [TypeScript] bug: required modal properties typed as undefined

Describe the bug Required modal properties are always typed as “<type> | undefined” instead of just “<type>”.

To Reproduce

Define a model like:

export const Cart = {
  pk: { type: String, value: '${_type}#${cartId}' },
  sk: { type: String, value: '${_type}#${cartId}' },

  cartId: { type: String, uuid: true, validate: /^[0-9A-Z]{26}$/i, required: true },
  total: { type: String },
};

export type CartType = Entity<typeof Cart>;

const cart: CartType = {
  cartId: '01FM4EY71FQSD8XK5TPWX722WJ', <---------- This is typed as "string | undefined"
  total: '100,00€',
};

I’m not a TypeScript expert so I can’t help doing a PR but changing “extends true” to “extends boolean” makes “cartId” field only of type “string” not “string | undefined” so I assume that the required field type must be checked as boolean and then as true:

export type Entity<T extends OneTypedModel> = UndefinedToOptional<{
  [P in keyof T]: T[P]['required'] extends true ? EntityField<T[P]> : EntityField<T[P]> | undefined;
}>;

Screenshots imagen imagen

Environment (please complete the following information):

  • OS: Mac OS 11.5.2
  • Node Version: v14.18
  • OneTable Version: v2.1.0 (latest)

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 17 (14 by maintainers)

Most upvoted comments

Ugh! Sorry. Will update immediately.

One more thing that is required with the 2.1.2+.

You must put “as const” after your model declarations. E.g.

    models: {
        User: {
            pk:         { type: String, value: 'Account#${accountId}' },
            sk:         { type: String, value: '${_type}#${id}' },
            id:         { type: String, uuid: true },
            name:       { type: String, required: true },
            email:      { type: String, required: true },
        },
    } as const

Got It!!!

Pretty readable too.

Now onto nested schemas (recursive types) Ugh!

/*
    Select the required properties from a model
*/
export type Required<T extends OneTypedModel> = {
    -readonly [P in keyof T as T[P]['required'] extends true ? P : never]: EntityField<T[P]>
};

/*
    Select the optional properties from a model
*/
export type Optional<T extends OneTypedModel> = {
    -readonly [P in keyof T as T[P]['required'] extends true ? never : P]?: EntityField<T[P]>
};

/*
    Merge two types
*/
type Merge<A, B> = { 
    [P in keyof (A & B)]: P extends keyof A ? A[P] : B[P]
};

/*
    Create entity type which includes required and optional types
*/
type Entity<T extends OneTypedModel> = Merge<Required<T>, Optional<T>>

@mobsense i am not either, but I’ll take a look tomorrow before noon