superstruct icon indicating copy to clipboard operation
superstruct copied to clipboard

combine `type` and `object` structs?

Open ianstormtaylor opened this issue 3 years ago • 2 comments

Curious to hear other perspectives on this.

Right now the only difference between type and object struct is the "looseness" of the properties. type doesn't care about unknown properties, whereas object is "strict" and throws when unknown properties are received.

I was thinking it might make sense to just make type a subset of object that is accessed via a { loose: true } option:

const Nameable = object({
  first_name: string(),
  last_name: string(),
}, {
  loose: true
})

Might be easier to find/understand for new users.

ianstormtaylor avatar Dec 12 '20 03:12 ianstormtaylor

Could also allow layering in the masked utility as { mask: true } as well, since it only applies to objects.

When doing either of these we'd ensure that object structs can be passed as schemes to new object structs, so that you can immutably change the settings, for example:

const User = object({
  id: number(),
  name: string(),
})

const PermissiveUser = object(User, { loose: true, mask: true })

ianstormtaylor avatar Dec 12 '20 18:12 ianstormtaylor

I use superstruct to validate configuration file. Sometimes someone might have a typo on the key field. I want the users to notice that mistake but I don't want to throw error and stop execution. So something like onExtraField will be useful.

const User = object({
  id: number(),
  name: string(),
  nickname: optional(string())
}, {
  // `onExtraField` is only valid when loose is `true`, so `onExtraField` is under `loose`
  loose: {
    onExtraField: fieldName => {
      console.log(`Unknown field '${fieldName}'`)
    }
  }
})

// Console output `Unknown field 'nicknmae'` without throwing error
User.assert({
  id: 1,
  name: 'Tony Stark',
  // Typo in the field name here
  nicknmae: 'Iron Man'
})

VeryCrazyDog avatar May 05 '22 03:05 VeryCrazyDog