joi
joi copied to clipboard
Type declaration for `messages` option of any.validate() inconsistent with the documentation and actual code
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:
-
Record<string, string | Record<string, string>>
-
Record<string, Record<string, string>>
-
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.
Exactly! run into this myself.
Having the same problem
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.
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);
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>>
.
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';