Есть ли способ получить как полезные, так и типовые знания из предиката типа в TypeScript? - PullRequest
0 голосов
/ 06 февраля 2019

При проверке данных иногда возникает вопрос: - допустимы ли данные - если нет, ошибки проверки

Можем ли мы сделать это естественным, JS-y способом в TypeScript?Работает ли что-то похожее на следующую?на master:

type Person = {
    name: string,
    height: number,
};

function validatePerson(obj: object, placeToPushValidationErrors: string[]): obj is Person {

    const missingKeys = ["dependencies", "name"]
        .filter(key => key in obj)
        .map(key => `key ${key} is missing from obj`);

    placeToPushValidationErrors.push(...missingKeys);

    return !missingKeys.length;
}

// imagine this is coming from untrustworthy JSON
function getHeight(): unknown {
    return 40;
}

const person = { name: "ff", height: getHeight() };
const validationErrors = [];
if (validatePerson(person, validationErrors)) {
    const p: Person = person;
}
else {
    throw Error(`invalid person: ${validationErrors.join(', ')}`)
}

1 Ответ

0 голосов
/ 07 февраля 2019

К сожалению, вы не можете использовать предикаты типа для этого.Их нельзя использовать в объединениях, пересечениях или в качестве типов свойств объекта.Единственное место, в котором они могут отображаться, - это тип возвращаемого значения для функции, и они привязаны только к одному параметру, переданному в функцию.И предикаты типа связаны с boolean так, как вам здесь не нужно, поскольку вы хотите, чтобы тип возвращаемого значения был массивом, но true и false не являются массивами.

В любом случае, я бы предложил сделать что-то другое здесь: вернуть объект, содержащий и нужный массив, и , необязательно a Person.Если присутствует Person, то проверка прошла успешно;в противном случае используйте массив ошибок проверки:

function validatePerson(obj: object) {

  const validationErrors = ["dependencies", "name"]
    .filter(key => key in obj)
    .map(key => `key ${key} is missing from obj`);

  const ret: { person?: Person, validationErrors: string[] } = { validationErrors };

  if (validationErrors.length === 0) {
    ret.person = obj as Person;
  }
  return ret;

}

declare const x: object;
const validatedPerson = validatePerson(x);

if (validatedPerson.person) {
  const b: Person = validatedPerson.person
} else {
  throw Error(`invalid person: ${validatedPerson.validationErrors.join(', ')}`)
}

Таким образом, вы используете validatedPerson.person в качестве защиты типов, и он автоматически сужается для вас.


Еще более кратким решением являетсясделать то, что предложила @ TitianCernicova-Dragomir, и вернуть либо Person, либо массив ошибок:

function validatePerson(obj: object) {
  const validationErrors = ["dependencies", "name"]
    .filter(key => key in obj)
    .map(key => `key ${key} is missing from obj`);
  return (validationErrors.length) ? validationErrors : (obj as Person);
}

declare const x: object;
const validatedPerson = validatePerson(x);

if (!Array.isArray(validatedPerson)) {
  const b: Person = validatedPerson;
} else {
  throw Error(`invalid person: ${validatedPerson.join(', ')}`)
}

Теперь тип возвращаемого значения validatePerson() равен Person | string[].Затем вы используете, является ли возвращаемый тип массивом в качестве охраны типа, и все это работает.


Надеюсь, они дадут вам несколько идей о том, как двигаться вперед.Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...