Skip to main content
Version: v0.9

Type Inference

Since the v0.4, most Entity methods types are inferred from an Entity definition. This is still experimental and may change in the future.

The following options are implemented:

  • 🔑 partitionKey, sortKey: They are used, along with array-based mapped attributes to infer the primary key type.
  • ⚡️ autoExecute, execute: If the execute option is set to false (either in the Entity definition or the method options), the method responses are typed as DocumentClient.<METHOD>ItemInput.
  • 🧐 autoParse, parse: If the parse option is set to false (either in the Entity definition or the method options), the method responses are typed as DocumentClient.<METHOD>ItemOutput.
  • ✍️ typeAlias, createdAlias, modifiedAlias: Aliases are used to compute the parsed responses types. They are also prevented from attribute definitions to avoid conflicts.
  • timestamps: If the timestamps option is set to false, createdAlias and modifiedAlias are omitted from the parsed responses types.
  • 👮 required: Attributes flagged as required are required as needed in put and update operations. They appear as always defined in parsed responses. Attempting to remove them, either with the $delete shorthand or by setting them to null causes an error.
  • 👍 default: Required attributes are not required in put and update operations if they have a default value. They appear as always defined in parsed responses.
  • ✂️ attributes: In get and queries operations, the attributes option filter the attributes of the parsed responses types.
  • ☝️ conditions: In put, update and delete operations, the conditions attributes are correctly typed.
  • 📨 returnValues: In put, update and delete operation, the returnValues option is interpreted to format the responses.
  • 🙈 hidden: Hidden attributes are omitted from the parsed responses types.
  • 🔗 dependsOn option: If the default property of a key attribute is a function, you can use the dependsOn attribute to enable typing the primary key through the depended-on attributes (i.e. those used in the function).

The following options are not yet implemented:

  • alias attribute option
  • Table attributes!
  • Secondary indexes names
  • coerce option
  • Improved list and set support ... And probably more! Feel free to open an issue if needed 🤗

Overlays

When type infering doesn't cut it, every method supports the possibility of enforcing a custom Item type, and a custom CompositeKey type where needed.

type CustomItem = {
pk: string
sk: string
name: string
}

type CustomCompositeKey = {
pk: string
sk: string
}

const { Item } = await MyEntity.get<
CustomItem,
CustomCompositeKey
>({
pk: 'pk',
sk: 'sk' // ✅ CustomCompositeKey expected
}) // ✅ Item is of type: undefined | CustomItem

Overlaying at the Entity level is also possible. The overlay is passed down to every method, and type inference is fully deactivated:

const MyEntity =  new Entity<"MyEntityName", CustomItem, CustomCompositeKey, typeof table>({
name: "MyEntityName",
...,
table,
} as const)

await MyEntity.update({ pk, sk, name }) // ✅ Overlay CustomItem is used
await MyEntity.delete<CustomItem, { foo: "bar" }>({ foo: "bar" }) // ✅ Entity overlays can still be overridden

Write operations condition and read operations attributes options are also typed as the applied overlay keys and filter the response properties:

const { Item } = await MyEntity.get(
{ pk, sk },
{ attributes: ['incorrect'] }
) // ❌ Errors
const { Item } = await MyEntity.get(
{ pk, sk },
{ attributes: ['name'] }
) // ✅ Item is of type { name: string }

Utility Types

EntityItem

The inferred or overlayed entity items type can be obtained through the EntityItem utility type:

import type { EntityItem } from 'dynamodb-toolbox'

const listUsers = async (): Promise<EntityItem<typeof UserEntity>[]> => {
const { Items } = await UserEntity.query(...)
return Items
}

Options

Sometimes, it can be useful to dynamically set an entity operation options. For instance:

const queryOptions = {}

if (!isSuperadmin(user)) {
queryOptions.beginsWith = 'USER'
}

const { Item } = await MyEntity.query(pk, {
attributes: ['name', 'age'],
...queryOptions
})

Sadly, in TS this throws an error, as getOptions is typed as {}. Using a non-generic GetOptions type also throws an error as the entity attribute names are hardly typed, and string is not assignable to the attributes or conditions options.

For this purpose, DynamoDB-Toolbox exposes GetOptions, PutOptions, DeleteOptions, UpdateOptions & QueryOptions utility types:

import type { QueryOptions } from 'dynamodb-toolbox'

const queryOptions: QueryOptions<typeof MyEntity> = {}

if (!isSuperadmin(user)) {
queryOptions.beginsWith = 'USER'
}

const { Item } = await MyEntity.query(pk, {
attributes: ['name', 'age'],
...queryOptions
})