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 theexecuteoption is set tofalse(either in the Entity definition or the method options), the method responses are typed asDocumentClient.<METHOD>ItemInput. - 🧐
autoParse,parse: If theparseoption is set tofalse(either in the Entity definition or the method options), the method responses are typed asDocumentClient.<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 thetimestampsoption is set to false,createdAliasandmodifiedAliasare omitted from the parsed responses types. - 👮
required: Attributes flagged asrequiredare required as needed inputandupdateoperations. They appear as always defined in parsed responses. Attempting to remove them, either with the$deleteshorthand or by setting them tonullcauses an error. - 👍
default: Required attributes are not required inputandupdateoperations if they have adefaultvalue. They appear as always defined in parsed responses. - ✂️
attributes: Ingetandqueriesoperations, theattributesoption filter the attributes of the parsed responses types. - ☝️
conditions: Input,updateanddeleteoperations, theconditionsattributes are correctly typed. - 📨
returnValues: Input,updateanddeleteoperation, thereturnValuesoption is interpreted to format the responses. - 🙈
hidden: Hidden attributes are omitted from the parsed responses types. - 🔗
dependsOnoption: If thedefaultproperty of a key attribute is a function, you can use thedependsOnattribute 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:
aliasattribute option- Table attributes!
- Secondary indexes names
coerceoption- Improved
listandsetsupport ... 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
})