Я пытаюсь обработать проверку модели в машинописном тексте. Я хотел бы иметь возможность фиксировать вложенные типы определения проверки.
Например, я хочу создать такой валидатор.
const validateUser = createValidator({
name: {
first: {
value: "First"
},
last: {
value: "Last"
}
},
age: {
value: 32
},
hasOnboarded: {
value: false
}
});
Это создаст функцию validateUser, которая принимает модель указанного type и проверяет его типы.
Я хотел бы иметь возможность фиксировать тип, чтобы validateUser знал, что нужно принять, объекты, соответствующие интерфейсу.
type ValidateUser = typeof validateUser;
Должен быть тип
(
model: {
name: {
first: string,
last: string
},
age: number,
hasOnboarded: boolean
}
) => boolean
Возможно ли это в TypeScript?






Это с использованием функций 2.8, условных типов и ключевого слова infer.
declare function createValidator<
T extends {
[key: string]: { value: any } | { [key: string]: { value: any } }
}>(modelDescriptor: T): (validationSubject: {
[key in keyof T]: T[key] extends { value: infer R }
? R
: {
[innerKey in keyof T[key]]: T[key][innerKey] extends { value: infer R } ? R : never
}
}) => boolean;
// const validateUser: (validationSubject: { name: { first: string; last: string; }; age: number; hasOnboarded: boolean; }) => boolean
const validateUser = createValidator({
name: {
first: {
value: "First"
},
last: {
value: "Last"
}
},
age: {
value: 32
},
hasOnboarded: {
value: false
}
});
Давайте разберемся с этим, так как это немного сложно.
Во-первых, наша функция принимает параметр типа T с ограничением, что это должен быть объект, где каждый ключ должен быть либо {value: any}, либо вложенным объектом, где каждый ключ является таким {value: any}.
Наш возвращаемый тип - это объект, так что для каждого ключа в T мы проверяем тип. Если это тип {value: <whatever>}, выведите <whatever> (и назовите его R), тип значения этого ключа - R (он же независимо от типа, который был у оригинала под ключом value).
Если он не относится к типу {value: <whatever>}, то по нашему исходному ограничению он должен иметь тип {[key: string]: {value: <whatever>}}, поэтому возвращаемый тип становится отображением второго уровня над этим внутренним объектом, снова извлекая тип того, что находится в value вложенного объекта.
Если это не так (что невозможно из-за нашего ограничения), тип возврата для ключа будет never. Эта часть никогда не должна быть достигнута.
@Cytren Это сделало бы TypeScript полной системой типов по Тьюрингу, а это не так. Боюсь, это невозможно сделать рекурсивно.
Спасибо, отлично работает. Однако он работает только на 2 уровня. Как вы думаете, можно ли сделать это рекурсивно, чтобы обеспечить бесконечную глубину?