tywalch / electrodb

A DynamoDB library to ease the use of modeling complex hierarchical relationships and implementing a Single Table Design while keeping your query code readable.
MIT License
956 stars 58 forks source link

Improve schema type using const type parameters #335

Open thorhj opened 7 months ago

thorhj commented 7 months ago

The entity schema is supposed to be unchangeable. Its purpose is to provide information for queries and typings.

I noticed this info box on the collections page:

TypeScript Note: Use as const syntax when defining collection as a string array for improved type support

This relates to sub-collections defined in the array syntax:

indexes: {
    projects: {
      collection: ["contributions", "assignments"] as const, // <--------------------------- HERE
      index: "gsi2",
      pk: {
        field: "gsi2pk",
        composite: ["employeeId"],
      },
      sk: {
        field: "gsi2sk",
        composite: [],
      },
    },
  },

I think this, and probably other similar cases, can be avoided using the const type parameters feature from Typescript 5. In index.d.ts I think every occurence of Schema can be made const in this way. For instance:

export class Entity<
  A extends string,
  F extends string,
  C extends string,
  const S extends Schema<A, F, C>, // <--------------------------- HERE
> { ... }

Here is a small contained example:

type Schema<C extends string> = {
  collection?: AccessPatternCollection<C>;
};

type AccessPatternCollection<C extends string> = C | ReadonlyArray<C>;

class Entity<C extends string, const S extends Schema<C>> {
  private schema: S;
  public constructor(schema: S) {
    this.schema = schema;
  }
}

const MyEntity = new Entity({
  collection: ["foo", "bar"],
});
/*
  const MyEntity: Entity<string, {
      readonly collection: readonly ["foo", "bar"];
  }>
*/

As you can see, MyEntity.collection is typed exactly like if we had used as const Using const type parameters is better than as const since it lessens the burden on the library consumers.

I haven't tested this, but my assumption is that every occurrence of

S extends Schema<A, F, C>

can be replaced with

const S extends Schema<A, F, C>

Caveats: