Ограничить значения объекта скалярами - PullRequest
1 голос
/ 11 апреля 2019

Я использую Formik, который имеет этот тип:

type FormikErrors<Values> = {
 [K in keyof Values]?: Values[K] extends object
  ? FormikErrors<Values[K]>
  : string
};

Тогда есть функция проверки, которая в основном выглядит как validate<Values>(v: Values) => FormikErrors<Values>. Идея состоит в том, что ключи FormikErrors совпадают с ключами Values ​​и сопоставляются со строковым сообщением об ошибке, ИЛИ рекурсивным объектом FormikErrors, если это поле представлено вложенным объектом.

Я пытаюсь написать универсальную функцию для проверки обязательных полей. Нужно работать только с плоскими значениями.

export function validateRequired<T, K extends keyof T>(values : T, names: K[]) : FormikErrors<T> {
 let errors : FormikErrors<T> = {};
 names.forEach((name) => {
  if (!values[name]) {
   errors[name] = 'This field is required';
  }
 });
 return errors;
}

Это ошибка, хотя:

Type error: Type '"This field is required"' is not assignable to type '(T[K] extends object ? FormikErrors<T[K]> : string) | undefined'. TS2322

Поскольку значения объекта, возвращаемого validateRequired, всегда являются строками, никогда не вкладывайте FormikValues. Есть ли способ указать, что значения всегда будут скалярами, чтобы можно было проверить тип?

1 Ответ

1 голос
/ 11 апреля 2019

Простым решением было бы не использовать тип FormikErrors.Используйте пользовательский тип, который может иметь только строковые значения:

type RequiredErrors<Values> = {
    [K in keyof Values]?: string
};

export function validateRequired<T, K extends keyof T>(values: T, names: K[]): RequiredErrors<T> {
    let errors: RequiredErrors<T> = {};
    names.forEach((name) => {
        if (!values[name]) {
            errors[name] = 'This field is required';
        }
    });
    return errors;
}

Если это не вариант для вас, тогда единственным решением является утверждение типа.Typescript не может разрешить условные типы, в которых все еще есть неразрешенные параметры универсального типа, и поэтому не может точно определить, является ли string допустимым значением для объекта errors, но утверждение типа исправит это:

export function validateRequired<T, K extends keyof T>(values: T, names: K[]): FormikErrors<T> {
    let errors: FormikErrors<T> = {};
    names.forEach((name) => {
        if (!values[name]) {
            errors[name] = 'This field is required' as any;;
        }
    });
    return errors;
}
...