Hi there,
I have declared an enum using nexus enumType function.
export const SubscriptionPlanEnum = enumType({
name: "SubscriptionPlanEnum",
members: {
SOLO: "soloID",
MULTI: "multiID",
}
});
but then I would like sometimes to use that enum as a type hint for a typescript function :
static async Test(plan : SubscriptionPlanEnum)
but it says that it seems to be a value not a type.
What is the best way to use that enum? If not possible, what is the best workaround?
Thank you very much!
The enumType from nexus will build a GraphQLEnumType under the hood which is not equivalent to a TypeScript enum.
If you're wanting to define an enum once and you'd like to use it both in TypeScript and in your schema, you can use define the enum in TypeScript and pass it to enumType (it will know how to extract the correct members out of it).
That would look something like this:
// User.ts
export enum UserRoles {
ADMIN = "admin",
EDITOR = "editor",
GUEST = "guest"
}
// Schema.ts
import { objectType, enumType } from "nexus";
import { UserRoles } from "./User";
// Pass the UserRoles enum straight into enumType
export const UserRoleEnumType = enumType({
name: "UserRole",
members: UserRoles
});
// You should be able to use it now just like this.
export const UserType = objectType({
name: "User",
definition(t) {
t.id("id");
t.field("role", {
type: "UserRole",
resolve: () => UserRoles.ADMIN
});
}
});
The generated schema will look as follows:
type User {
id: ID!
role: UserRole!
}
enum UserRole {
ADMIN
EDITOR
GUEST
}
...and the corresponding type definitions will look like this:
export interface NexusGenEnums {
UserRole: "admin" | "editor" | "guest"
}
This should be sufficient if you're only going to use the enum as a return type. If you're also going to accept it as input types and you want to have this work properly with TypeScript you'll need additional source in the typegenAutoConfig of your makeSchema call.
For example if you want to use your enum as input for a mutation like so:
function updateUserRole(role: UserRoles) {
// update the users role...
}
export const UpdateUserRole = mutationField("updateUserRole ", {
type: "User",
args: {
role: arg({ type: "UserRole", nullable: false })
},
resolve: (_, args) => {
return updateUserRole(args.role);
}
});
If you don't set up a proper source you'll notice that TypeScript will not let you go from "admin" | "editor" | "guest" to a UserRoles enum type. This is normal for TypeScript. If you want nexus to fix this for you, you can add a source config like so:
makeSchema({
types: [UserType, UserRoleEnumType, UpdateUserRole],
outputs: {
schema: path.join(__dirname, "./schema.graphql"),
typegen: path.join(__dirname, "./types..d.ts")
},
typegenAutoConfig: {
sources: [
{
alias: "usr",
source: path.join(__dirname, "./User.ts"),
typeMatch: name =>
// the default implementation doesn't include enum in the regex.
new RegExp(`(?:interface|type|class|enum)\\s+(${name}s?)\\W`, "g")
}
}
]
}
});
What will happen now is that nexus should find the UserRoles name match and import an alias into the type definitions like so:
import * as usr from "./User"
export interface NexusGenEnums {
UserRole: usr.UserRoles
}
This will now also reflect in the types for the args argument in your resolver and the types should match.
As far as I know this is the most elegant way thus far to only define an enum once and use it in both your schema and code.
You are awesome!! That couldn鈥檛 be more helpful! Thank you very much, I鈥檒l setup it right away. Cheers
Most helpful comment
The
enumTypefromnexuswill build aGraphQLEnumTypeunder the hood which is not equivalent to a TypeScript enum.If you're wanting to define an
enumonce and you'd like to use it both in TypeScript and in your schema, you can use define theenumin TypeScript and pass it toenumType(it will know how to extract the correct members out of it).That would look something like this:
The generated schema will look as follows:
...and the corresponding type definitions will look like this:
This should be sufficient if you're only going to use the enum as a return type. If you're also going to accept it as input types and you want to have this work properly with TypeScript you'll need additional source in the
typegenAutoConfigof yourmakeSchemacall.For example if you want to use your enum as input for a mutation like so:
If you don't set up a proper source you'll notice that TypeScript will not let you go from
"admin" | "editor" | "guest"to aUserRolesenum type. This is normal for TypeScript. If you wantnexusto fix this for you, you can add a source config like so:What will happen now is that
nexusshould find theUserRolesname match and import an alias into the type definitions like so:This will now also reflect in the types for the
argsargument in your resolver and the types should match.As far as I know this is the most elegant way thus far to only define an enum once and use it in both your schema and code.