При проверке данных иногда требуется: - действительны ли данные - если нет, ошибки проверки
Можем ли мы сделать это естественным, JS-способом в TypeScript? Работает ли что-то вроде следующего?
type Person = {
name: string,
height: number,
};
function validatePerson(obj: object): obj is Person & string[] {
const missingKeys = ["dependencies", "name"]
.filter(key => key in obj)
.map(key => `key ${key} is missing from obj`);
if (!missingKeys.length) {
return missingKeys as typeof missingKeys & true;
}
else {
return missingKeys as typeof missingKeys & false;
}
}
const x = { name: "ff", height: getHeight()};
const validationErrors = validatePerson(x);
if (!validationErrors.length) {
const b: Person = x;
}
function getHeight(): any {
return 40;
}
Лучшее, что я могу заставить на самом деле работать, это эта странная штука в стиле передачи указателя, но мне просто недостаточно JS-y, чтобы хотеть это на 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(', ')}`)
}
К сожалению, определяемые пользователем типы защиты типа в форме x is Y на самом деле не являются первоклассными гражданами и не могут перемещаться или компоноваться так, как это могут делать другие типы. Таким образом, вы не можете вернуть что-то вроде {isValid: obj is Person, validationErrors: string[]}. Вы можете отказаться от защиты типов и вернуть что-то вроде {person?: Person, validationErrors: string[]}, а затем использовать, определено ли свойство person как защита.
@jcalz, если вы сделаете свой комментарий ответом, я отмечу его правильным. Это действительно интересное предложение.






К сожалению, для этого нельзя использовать предикаты типов. Их нельзя использовать в объединениях, пересечениях или в качестве типов свойств объекта. Единственное место, где они действительно могут появиться, — это тип возвращаемого значения для функции, и они привязаны ровно к одному параметру, переданному в функцию. И предикаты типа связаны с 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[]. Затем вы используете, является ли возвращаемый тип массивом или нет, в качестве защиты типа, и все это работает.
Надеюсь, они подскажут вам, как двигаться дальше. Удачи!
Нет, пользовательская защита типа должна возвращать
param is type. Вы можете вернутьPerson | string[], поместить его в переменную и использоватьif ( usa_bbox instanceof Array).