Fix issues with enum options filtering logic in enum_ function #941
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The current implementation of the enum_ function in Valibot filters enum options using the following code:
valibot/library/src/schemas/enum/enum.ts
Lines 92 to 98 in 8ab047f
The purpose of this filtering logic is to remove the reverse mapping entries that TypeScript adds when transpiling enums. Specifically, when an enum member is defined as Name = value and value is a number, TypeScript generates a reverse mapping in the form
Enum[value] = 'Name'
. The key of this reverse mapping is stringified by Number.prototype.toString with radix=10 via ToPropertyKey as defined by the ECMAScript specification.There are several issues with using
+key
andisNaN
in the filtering logic:String Conversion: The +key operation follows the StringToNumber abstract operation as defined in the ECMAScript specification. Since
enum_
filters out any number, this operation has several implications:Infinity
or-Infinity
are interpreted as their respective number representations.0b
,0o
, or0x
as binary, octal, or hexadecimal literals.0.1
,.1
, and0
. are all valid and yield the respective numeric values.+
symbol as a valid sign.NaN Values in Enum: If the enum contains
NaN
, as in the following example:The
isNaN
check will not work as expected sinceisNaN(key)
will return true when key is 'NaN', causing the 'NaN' key to be retained rather than filtered out.To correctly filter out these reverse mappings, I made the filtering logic more precise. In this PR, rather than
isNaN
, the parsed value is stringified and is matched against the original key. If it matches, it is filtered out.Additionally, the filtering logic is not reflected in the
EnumSchema
type. For example, when usingenum_({ 1: "A" })
, theoptions
end up being empty, which was not obvious until runtime. Therefore I implemented type-level option filtering.