Repository: typestack/class-validator (ts)

Issue:
Ability to use constant array as `IsIn` and `IsNotIn` argument
Constant array can not be passed as `IsIn` argument, which is a common thing to validate against a constant array not a dynamic list. Example:

```
const Currencies = ['ETH', 'BTC'] as const;

class Payment {
  @IsIn(Currencies)
  currency: string
}
```

Generates compilation error:

```
Argument of type 'readonly ["ETH", "BTC"]' is not assignable to parameter of type 'any[]'. The type 'readonly ["ETH", "BTC"]' is 'readonly' and cannot be assigned to the mutable type 'any[]'
```

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions
Fixable by using `readonly any[]` as argument types instead of `any[]`.


Pull request description:
feat: allow readonly array argument for IsIn IsNotIn validators
Fixed #596.

Patch:
diff --git a/src/decorator/common/IsIn.ts b/src/decorator/common/IsIn.ts
index 4bbd631..0773d33 100644
--- a/src/decorator/common/IsIn.ts
+++ b/src/decorator/common/IsIn.ts
@@ -6,14 +6,14 @@ export const IS_IN = "isIn";
 /**
  * Checks if given value is in a array of allowed values.
  */
-export function isIn(value: unknown, possibleValues: unknown[]): boolean {
+export function isIn(value: unknown, possibleValues: readonly unknown[]): boolean {
     return !(possibleValues instanceof Array) || possibleValues.some(possibleValue => possibleValue === value);
 }
 
 /**
  * Checks if given value is in a array of allowed values.
  */
-export function IsIn(values: any[], validationOptions?: ValidationOptions): PropertyDecorator {
+export function IsIn(values: readonly any[], validationOptions?: ValidationOptions): PropertyDecorator {
     return ValidateBy(
         {
             name: IS_IN,
diff --git a/src/decorator/common/IsNotIn.ts b/src/decorator/common/IsNotIn.ts
index 255fb68..24d1302 100644
--- a/src/decorator/common/IsNotIn.ts
+++ b/src/decorator/common/IsNotIn.ts
@@ -6,14 +6,14 @@ export const IS_NOT_IN = "isNotIn";
 /**
  * Checks if given value not in a array of allowed values.
  */
-export function isNotIn(value: unknown, possibleValues: unknown[]): boolean {
+export function isNotIn(value: unknown, possibleValues: readonly unknown[]): boolean {
     return !(possibleValues instanceof Array) || !possibleValues.some(possibleValue => possibleValue === value);
 }
 
 /**
  * Checks if given value not in a array of allowed values.
  */
-export function IsNotIn(values: any[], validationOptions?: ValidationOptions): PropertyDecorator {
+export function IsNotIn(values: readonly any[], validationOptions?: ValidationOptions): PropertyDecorator {
     return ValidateBy(
         {
             name: IS_NOT_IN,


Test patch:
diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts
index f91c62f..41d9862 100644
--- a/test/functional/validation-functions-and-decorators.spec.ts
+++ b/test/functional/validation-functions-and-decorators.spec.ts
@@ -437,7 +437,7 @@ describe("IsNotEmpty", () => {
 });
 
 describe("IsIn", () => {
-    const constraint = ["foo", "bar"];
+    const constraint = ["foo", "bar"] as const;
     const validValues = ["foo", "bar"];
     const invalidValues = ["foobar", "barfoo", ""];
 
@@ -470,7 +470,7 @@ describe("IsIn", () => {
 });
 
 describe("IsNotIn", () => {
-    const constraint = ["foo", "bar"];
+    const constraint = ["foo", "bar"] as const;
     const validValues = ["foobar", "barfoo", ""];
     const invalidValues = ["foo", "bar"];