joi icon indicating copy to clipboard operation
joi copied to clipboard

Type declaration for `messages` option of any.validate() inconsistent with the documentation and actual code

Open kmbt opened this issue 3 years ago • 1 comments

Context

  • node version: v16.13.1
  • module version with issue: 17.5.0
  • last module version without issue: ?
  • environment (e.g. node, browser, native): node
  • used with (e.g. hapi application, another framework, standalone, ...): standalone
  • any other relevant information:

What are you trying to achieve or the steps to reproduce?

I am trying to supply localized error messages as documented here: https://github.com/sideway/joi/blob/master/API.md#anyvalidatevalue-options

The documentation for options.errors.language states that the messages object is a 'two-dimensional' object:

The value is matched against keys at the root of the messages object, and then the error code as a child key of that

, thus I try to use schema.validate() the following way:

import Joi, { LanguageMessages } from "joi";

const validationMessages = {
  'en': {
    'string.empty': 'XYZ',
  }
}

const schema = Joi.object({
  key: Joi.string()
})

schema.validate({}, {
  errors: {
    language: 'en'
  },
  messages: validationMessages
})

What was the result you got?

A typescript error on messages option:

Type '{ en: { 'string.empty': string; }; }' is not assignable to type 'LanguageMessages'.
  Property ''en'' is incompatible with index signature.
    Type '{ 'string.empty': string; }' is not assignable to type 'string'.ts(2322)

Looking into the library code I have found that the type for messages given here: https://github.com/sideway/joi/blob/b4dbd59371be9d0fbbaa5f561d5aef929028ad99/lib/index.d.ts#L181-L190 is LanguageMessages which is defined here: https://github.com/sideway/joi/blob/b4dbd59371be9d0fbbaa5f561d5aef929028ad99/lib/index.d.ts#L29

, which is just a flat object.

What result did you expect?

I would expect, that the required type for messages is declared as one of the following:

  1. Record<string, string | Record<string, string>>
  2. Record<string, Record<string, string>>
  3. Record<string, string> | Record<string, Record<string, string>>

Option 1. seems to most accurately describe the data shape actually accepted as the messages option. It actually seems possible to provide a flat object with just error keys or a mixed one, as such:

const validationMessages : T = {
  'es': {
    'string.empty': 'XYZ',
  },
  'pl': {
    'string.empty': 'KLM',
  },
  'string.empty': 'PQR'
}

, while Option 2. reflects the documentation for validate() best.

kmbt avatar Jan 08 '22 20:01 kmbt

Exactly! run into this myself.

eladchen avatar Jan 21 '22 20:01 eladchen

Having the same problem

atresca-globant avatar Jun 28 '23 15:06 atresca-globant

Is there any solution to this issue? I'm using typescript and I've found your blog entry but I cannot make it work because the compilation issue.

calbertts avatar Aug 24 '23 10:08 calbertts

Is there any solution to this issue? I'm using typescript and I've found your blog entry but I cannot make it work because the compilation issue.

If anyone else has this doubt, this is the way:

const validationOptions = { ... }
const validate = schema.validate(payload, validationOptions as unknown as Joi.ValidationOptions);

calbertts avatar Aug 24 '23 12:08 calbertts

Can confirm this is still an issue. It was really annoying. Found out the type declaration was wrong, because language keys are supported in this function: https://github.com/hapijs/joi/blob/81277bd9123392cd0b8447065d8615e480b04613/lib/errors.js#L118 Type declaration for the messages schema can be found here: https://github.com/hapijs/joi/blob/81277bd9123392cd0b8447065d8615e480b04613/lib/index.d.ts#L29

The most accurate type would indeed be Record<string, string | Record<string, string>>.

jacobkapitein avatar Jan 02 '24 14:01 jacobkapitein

I created a quick patch with ts-patch.

Use this to fix any errors you might encounter:

diff --git a/node_modules/joi/lib/index.d.ts b/node_modules/joi/lib/index.d.ts
index da367a9..3ed262e 100644
--- a/node_modules/joi/lib/index.d.ts
+++ b/node_modules/joi/lib/index.d.ts
@@ -26,7 +26,7 @@ declare namespace Joi {
 
     type BasicType = boolean | number | string | any[] | object | null;
 
-    type LanguageMessages = Record<string, string>;
+    type LanguageMessages = Record<string, string | Record<string, string>>;
 
     type PresenceMode = 'optional' | 'required' | 'forbidden';

jacobkapitein avatar Jan 02 '24 15:01 jacobkapitein