SignupHandlerOptions userAttributes type

I was wondering why the userAttributes attribute on the signup handler has the type Record<string, string>. Here’s the relevant code:
I find myself having numbers and arrays in my userAttributes making typescript complain and me having to do stuff like: const { age, nums } = userAttributes as unknown as { age: number; nums: number[] }.
Wouldn’t it make more sense to have the type as Record<string, any> so we don’t have to deal with type conversions? I can’t see people just having strings in the userAttributes.

I would think a PR applying a generic to userAttributes with a default type (and exporting it) would be accepted by the project:

type JsonPrimitive = string | number | boolean | null
interface JsonArray extends Array<JsonPrimitive | JsonArray | JsonMap> {}
interface JsonMap extends Record<string, JsonPrimitive | JsonArray | JsonMap> {}
type Json = JsonPrimitive | JsonMap | JsonArray

export interface SignupHandlerOptions<T = Record<string, bigint | boolean | Date | null | number | string | Json | undefined>> {
  username: string
  hashedPassword: string
  salt: string
  userAttributes?: T

The userAttributes value isn’t valid as any type. Objects must be serialized before being persisted. Symbols, Sets and Maps aren’t valid PostgreSQL data types. Conversely, TypeScript can’t represent a NaN type (though PostgreSQL can persist it) and NaNs are narrowed to a number type.

If you’d rather not push a PR, let me know and I’ll push one. It seems like the JSON type should be a utility type somewhere in Redwood (or imported). I don’t see any packages that can be added as a dependency to provide it. Since dbAuth is in a package, I don’t see any good place to include the JSON type as a utility type available to all packages.

I’ll put a PR together, I think that at least exporting the SignupHandlerOptions interface would allow to extend it and replace the userAttributes type with a custom type.

What’s the difference in saying Record<string, any> or Record<string, list of every type possible>? Till you read the value you are not gonna know the type either way.

You’re right, the userAttributes data is coming from a form so my suggestion isn’t correct. The form value types are narrowed to database types in signup.handler().

I’d suggest using Record<string, unknown> over Record<string, any>. Good luck!

Support for this was finally merged. Should be released in the next minor version of RW (out this or next week)

1 Like