Skip to content

fix: reject enum member names in @IsEnum for numeric enums#2685

Open
spokodev wants to merge 1 commit into
typestack:developfrom
spokodev:fix/isenum-reject-member-names
Open

fix: reject enum member names in @IsEnum for numeric enums#2685
spokodev wants to merge 1 commit into
typestack:developfrom
spokodev:fix/isenum-reject-member-names

Conversation

@spokodev

@spokodev spokodev commented Jul 2, 2026

Copy link
Copy Markdown

@IsEnum and isEnum() accept the enum member NAME as a valid value for numeric and default-indexed enums. TypeScript compiles a numeric enum to a bidirectional map, so Object.keys(entity).map(k => entity[k]) includes the reverse-map names in the accepted set.

For enum Direction { Up = 1, Down = 2 } the only valid values are 1 and 2, but @IsEnum(Direction) also accepts the strings "Up" and "Down". A request body { direction: "Up" } passes validation and reaches the handler as a string where the code expects a number. The library's own default error message already lists only 1, 2 (it is built from validEnumValues), so the validator accepts values its own message declares invalid.

This is the bug tracked in #1060 (open, labeled type: fix).

Fix

isEnum now builds its accepted set from validEnumValues, the same helper the @IsEnum decorator already uses for the error message, which keeps only the entries whose key is non-numeric:

const enumValues = validEnumValues(entity);
return enumValues.includes(value as string);

Genuine values still match (runtime includes uses strict equality, so numbers match numbers and strings match strings); the reverse-map names and numeric key strings no longer do.

Added regression tests to the existing IsEnum describe block: the member name and the reverse-mapped numeric key are rejected for numeric and default-indexed enums, genuine values still pass, and the decorator fails when a member name is passed. The full suite (810) stays green.

This is distinct from #2099, which changes how companion-namespace function values appear in the message, not the accepted set.

TypeScript compiles a numeric enum to a bidirectional map, so
Object.keys(entity).map(k => entity[k]) included the reverse-map member
names in the accepted set. @IsEnum(NumericEnum) then accepted the member
NAMES (e.g. 'Up' for { Up = 1 }) as valid, letting a string through where
a number is expected. The default error message already lists only the
real values, built from validEnumValues, so the validator accepted values
its own message declared invalid.

Build the accepted set from validEnumValues, the same helper the decorator
already uses for the message. Fixes typestack#1060.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant