andreypopp / validated

Validate your configurations with precise error messages
91 stars 14 forks source link

Enumeration of strings doesn't match to Flow Union #17

Closed dfalling closed 6 years ago

dfalling commented 6 years ago
const schema = object({
  layout = enumeration('horizontal', 'vertical')
})

type LayoutType = {
  layout: 'horizontal' | 'vertical'
}

const validatedData: LayoutType = validateObject(schema, data)

Validated is returning a mixed type for the enumeration, while Flow expects a string enum. Is there a good way to handle this? Right now I'm explicitly converting:

return layout === 'vertical' ? 'vertical' : 'horizontal';

Thanks!

dfalling commented 6 years ago

A more reusable workaround I've come up with...

// $FlowFixMe
const identity = (data: T): T => data;

I pass any enumerations through this so the Flow error is muted, but any other Validation errors bubble up. I'd love a better workaround though.

LoganBarnett commented 6 years ago

@dfalling we ran into the same problem, and for now we use this pattern as a strictly typed workaround:

export class MyEnumNode extends v.Node<MyEnum> {
  validate (context: Context) {
    const prevalidator = v.string
    const { value, context: nextContext } = prevalidator.validate(context)
    if (value === 'foo' ||
        value === 'bar' ||
        value === 'baz'
    ) {
      return { value, context: nextContext }
    } else {
      throw context.error(context, 'This is not a MyEnumNode: ' + String(value))
    }
  }
}

// consumed

validateObject(object({ enum: new MyEnumNode() }), data)
dfalling commented 6 years ago

Thanks @LoganBarnett that's great. I wish it was easier but that's a much better workaround than my hacks.

pronebird commented 6 years ago

I have the same problem. Weird that the following trick doesn't work either:

object({
  notification_type: enumeration(...([
    'INITIAL_BUY',
    'CANCEL',
    'RENEWAL',
    'INTERACTIVE_RENEWAL',
    'DID_CHANGE_RENEWAL_PREFERENCE'
  ]: Array<StatusUpdateNotificationType>)),
});
andreypopp commented 6 years ago

v1.1.3 does it but you need to provide a type manually when constructing a validator:

function test_enum() {
  const schema: s.EnumerationNode<'a' | 'v'> = s.enumeration('a', 'v');
  const data = o.validate(schema, 'a');
  (data: 'a' | 'v');
  (data: string);
  // $ExpectError
  (data: number);
}