如何用TypeScript泛型正确关联函数参数?优化makeValidate类型
优化表单验证工具函数的泛型类型定义,消除冗余断言
想用happyValidate替代手写的sadValidate,但无法正确实现makeValidate的泛型类型定义。目前通过添加大量as断言能让代码运行,但希望优化类型标注,去掉这些冗余断言。
原始代码示例
type ValidationFn = (s: string) => boolean; interface Validation { check: ValidationFn; message: string; } const validIdentityNameCharacters = /^[a-zA-Z0-9_.-\s]*$/; const hasSpecialCharacters: Validation = { check: s => !validIdentityNameCharacters.test(s), message: 'Must only include letters, numbers and the following special characters: (_ -.)', }; const LIMIT = 255; const isLengthTooLong: Validation = { check: s => s.length >= LIMIT, message: `Must be less than ${LIMIT} characters`, }; const isBlank: Validation = { check: s => s === '', message: 'Must not be blank' }; interface Values { name: string; tags: string; } const sadValidate = (values: Values): Partial<Values> => { const errors: Partial<Values> = {}; const { name, tags } = values; if (hasSpecialCharacters.check(name)) { errors.name = hasSpecialCharacters.message; } else if (isLengthTooLong.check(name)) { errors.name = isLengthTooLong.message; } else if (isBlank.check(name)) { errors.name = isBlank.message; } if (isLengthTooLong.check(tags)) { errors.tags = isLengthTooLong.message; } return errors; }; const makeValidate = config => values => Object.keys(config).reduce((acc, fieldName) => { const validators = config[fieldName]; const problem = validators.find(({ check }) => check(values[fieldName])); if (problem) { acc[fieldName] = problem.message; } return acc; }, {}); const happyValidate = makeValidate({ name: [hasSpecialCharacters, isLengthTooLong, isBlank], tags: [isLengthTooLong], }); test('works', () => { expect(happyValidate({ name: '', tags: new Array(260).fill('a').join('') })).toEqual({ name: isBlank.message, tags: isLengthTooLong.message, }); });
当前带大量as断言的可行实现
export const makeValidate = <V>(config: Record<keyof V, Validation[]>) => (values: V): Record<keyof V, string> => Object.keys(config).reduce<Record<keyof V, string>>((acc, fieldName) => { const validators = config[fieldName as keyof V]; const problem = validators.find(({ check }) => check(values[fieldName as keyof V] as string)); if (problem) { acc[fieldName as keyof V] = problem.message; } return acc; }, {} as Record<keyof V, string>);
内容的提问来源于stack exchange,提问作者mholm815
相关产品推荐
相关产品推荐

