Я думаю, здесь есть две проблемы. В Validation<T, E>
, полученном из интерфейса, подобного StudentSchema
, он имеет те же ключи, что и StudentSchema
, и для каждого ключа K
тип T
является типом соответствующего свойства StudentSchema[K]
. Эта часть идеально подходит для отображаемых типов . Это будет выглядеть примерно так:
/* type ValidationFor<T> = { [K in keyof T]: Validation<T[K], ...>}; */
/* type ValidationForStudentSchema = ValidationFor<StudentSchema>; */
, где ...
- это пока неизвестная вещь, которую мы хотим сделать для E
. То, что вы могли бы сделать здесь, - это создать объект другого типа E
, который имеет те же ключи, что и StudentSchema
, свойства которого используются для подключения к E
в Validation
. Это будет выглядеть примерно так:
type ValidationFor<T, E extends Record<keyof T, any>> =
{ [ K in keyof T ]: Validation<T[K], E[K]> };
type ValidationForStudentSchema<E extends Record<keyof StudentSchema, any>> =
ValidationFor<StudentSchema, E> */
И тогда ваш пример StudentValidations
будет иметь следующий тип:
const StudentValidations: ValidationFor<StudentSchema, {
name: { required: string },
country: { required: string; },
age: { required: string; },
id: { required: string; match: string; max: (max: number) => string; }
}> = ...;
Но для этого потребуется либо явно выписать это E
тип объекта, или попытайтесь заставить компилятор выводить его, ни один из которых не особенно интересен.
Вместо этого я бы предложил ослабить ограничение на свойства E
и используйте намеренно "все, что идет" тип any
:
/* type ValidationFor<T> = { [K in keyof T]: Validation<T[K], any> }; */
Это работает; ValidationFor<StudentSchema>
будет соответствовать желаемым значениям, но это слишком "забывчиво"; поскольку он будет использовать any
вместо фактического E
свойства, которое вы ему дадите. Чтобы помнить компилятор, мы создаем вспомогательную функцию generi c, которая просто принимает значение типа generi c, extends ValidationFor<StudentSchema>
:
const valsForStudentSchema =
<U extends { [K in keyof StudentSchema]: Validation<StudentSchema[K], any> }>(
valMap: U
) => valMap;
Если Вы передаете аргумент valsForStudentSchema()
, который не соответствует ValidationFor<StudentSchema>
, вы получите ошибку. Если вы передадите аргумент, что соответствует , компилятор просто вернет его, не расширив его до ValidationFor<StudentSchema>
и не забыв.
Вот так:
const StudentValidations = valsForStudentSchema({
name: {
foo: 'AAA',
bar: 1,
validation: (errorMessages?: { required: string }): SchemaValidation<string> =>
new StringSchemaValidation()
.setIsRequired(errorMessages?.required),
},
id: {
foo: 'BBB',
bar: 2,
validation: (errorMessages?: { required: string; match: string; max: (max: number) => string }): SchemaValidation<string> =>
new StringSchemaValidation()
.setIsRequired(errorMessages?.required)
.setMatches(/[a-zA-Z0-9]+/, errorMessages?.match)
.setMax(30, errorMessages?.max(30)),
},
country: {
foo: 'CCC',
bar: 3,
validation: (errorMessages?: { required: string }): SchemaValidation<string> =>
new StringSchemaValidation()
.setIsRequired(errorMessages?.required),
},
age: {
foo: 'DDD',
bar: 4,
validation: (errorMessages?: { required: string }): SchemaValidation<number> =>
new NumberSchemaValidation()
.setIsRequired(errorMessages?.required),
},
});
Обратите внимание, что вы спрашивали о наличии чего-то, что работает с другими схемами, а не только с StudentSchema
. Мы можем сделать это с помощью curry , создав функцию generi c, которая принимает тип схемы и возвращает другую функцию generi c, которая создает ValidationFor
такого типа:
const validationFor = <T>() => <U extends { [K in keyof T]: Validation<T[K], any> }>(
valMap: U
) => valMap;
const StudentValidations = validationFor<StudentSchema>()({
// ... put the same object here as before
});
И вы можете использовать его с другим типом, подобным этому:
interface Foo {
a: boolean
}
const foo = validationFor<Foo>()({
a: {
foo: "",
bar: 1,
validation: (e?: { a: string }): SchemaValidation<boolean> =>
new BooleanSchemaValidation()
}
})
Хорошо, надеюсь, это поможет; удачи!
Детская площадка ссылка на код