Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Additional type safety for enum default values #26

Open
zygopleural opened this issue Sep 30, 2022 · 3 comments
Open

Additional type safety for enum default values #26

zygopleural opened this issue Sep 30, 2022 · 3 comments
Labels
enhancement New feature or request

Comments

@zygopleural
Copy link
Contributor

zygopleural commented Sep 30, 2022

Given an enum

const PlanType = createEnum((PlanType) => {
  PlanType
    .addValue("FREE")
    .addValue("PREMIUM")
})

and a model

const Plan = createModel((Plan) => {
  Plan
    .string("name", { id: true })
    .enum("type", PlanType, { default: "FREE" })
})

I want to ensure that the value passed as the default argument for the enum (e.g. { default: "FREE" }) is a valid value of the enum (i.e. ["FREE", "PREMIUM"]).

At the moment I am able to pass anything (e.g. .enum("type", PlanType, { default: "SOMETHING" })).

@jmackie
Copy link

jmackie commented Sep 30, 2022

FWIW I had a little play with this and it ends up looking like

export class PrismaEnum<Values = never> {
  private enumMap: Map<string, string | undefined> = new Map();

  constructor(public readonly name: string) {}

  public addValue<Values, Value extends string>(
    this: PrismaEnum<Values>,
    value: Value,
    options?: PrismaEnumOptions
  ): PrismaEnum<Values | Value> {
    // We need to return a new instance with a cloned `enumMap` 
    // for the types to do what we want.
    // If we modify `enumMap` in place then the type of `this` will be "wrong".
    const clone = new PrismaEnum(this.name);
    clone.enumMap = new Map(this.enumMap);
    clone.enumMap.set(value, options?.map);
    return clone;
  }

  // ...etc
}

Which then gives you typing like

// e.g.
const test: PrismaEnum<"foo" | "baz"> = new PrismaEnum("test")
  .addValue("foo")
  .addValue("baz");

Although this doesn't fit nicely with the create* functions where the callback is expected to mutate the values in place...

@ridafkih
Copy link
Owner

Are we looking for Intellisense/Type-checking, or runtime checks?

Since, as @jmackie specified, the values are altered in place we'd have to go a roundabout way of making the values available to the TypeScript language server. One way would be to return the value of the alteration and build the strings onto the enum constructor type. Otherwise, we could have it default to "string" as we currently do.

@ridafkih
Copy link
Owner

Another way would be supporting as such.

const PlanType = createEnum<"foo", "baz">((PlanType) => {
  PlanType
    .addValue("foo")
    .addValue("baz")
})

A little verbose, though.

@ridafkih ridafkih added the enhancement New feature or request label May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants