mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2024-12-09 04:31:35 +08:00
fix(form): fix async-validator related types
This commit is contained in:
parent
7e9784a6d3
commit
df73044c24
@ -11,18 +11,18 @@ You can use `n-form-item` alone, without `n-form`.
|
|||||||
```js
|
```js
|
||||||
import { defineComponent, ref } from 'vue'
|
import { defineComponent, ref } from 'vue'
|
||||||
|
|
||||||
const lyrics = 'It is not in Form'
|
const message = 'It is not in Form'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup () {
|
setup () {
|
||||||
const valueRef = ref(lyrics)
|
const valueRef = ref(message)
|
||||||
return {
|
return {
|
||||||
value: valueRef,
|
value: valueRef,
|
||||||
rule: {
|
rule: {
|
||||||
trigger: ['input', 'blur'],
|
trigger: ['input', 'blur'],
|
||||||
validator () {
|
validator () {
|
||||||
if (valueRef.value !== lyrics) {
|
if (valueRef.value !== message) {
|
||||||
return new Error(lyrics)
|
return new Error(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,18 +11,18 @@
|
|||||||
```js
|
```js
|
||||||
import { defineComponent, ref } from 'vue'
|
import { defineComponent, ref } from 'vue'
|
||||||
|
|
||||||
const lyrics = '它不在 Form 里面'
|
const message = '它不在 Form 里面'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup () {
|
setup () {
|
||||||
const valueRef = ref(lyrics)
|
const valueRef = ref(message)
|
||||||
return {
|
return {
|
||||||
value: valueRef,
|
value: valueRef,
|
||||||
rule: {
|
rule: {
|
||||||
trigger: ['input', 'blur'],
|
trigger: ['input', 'blur'],
|
||||||
validator () {
|
validator () {
|
||||||
if (valueRef.value !== lyrics) {
|
if (valueRef.value !== message) {
|
||||||
return new Error(lyrics)
|
return new Error(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
Transition,
|
Transition,
|
||||||
renderSlot
|
renderSlot
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import Schema, { ErrorList, ValidateOption } from 'async-validator'
|
import Schema, { ErrorList, RuleItem, ValidateOption } from 'async-validator'
|
||||||
import { get } from 'lodash-es'
|
import { get } from 'lodash-es'
|
||||||
import { createId } from 'seemly'
|
import { createId } from 'seemly'
|
||||||
import { formItemInjectionKey } from '../../_mixins/use-form-item'
|
import { formItemInjectionKey } from '../../_mixins/use-form-item'
|
||||||
@ -36,6 +36,7 @@ import {
|
|||||||
LabelPlacement,
|
LabelPlacement,
|
||||||
ValidateCallback,
|
ValidateCallback,
|
||||||
ValidationTrigger,
|
ValidationTrigger,
|
||||||
|
FormItemRuleValidatorParams,
|
||||||
FormItemRuleValidator,
|
FormItemRuleValidator,
|
||||||
FormItemValidateOptions,
|
FormItemValidateOptions,
|
||||||
FormItemInst,
|
FormItemInst,
|
||||||
@ -87,27 +88,38 @@ export type FormItemProps = ExtractPublicPropTypes<typeof formItemProps>
|
|||||||
export const formItemPropKeys = keysOf(formItemProps)
|
export const formItemPropKeys = keysOf(formItemProps)
|
||||||
|
|
||||||
// Wrapped Validator is to be passed into async-validator
|
// Wrapped Validator is to be passed into async-validator
|
||||||
|
// In their source code, validator can be a asyncValidator.
|
||||||
|
// asyncValidator will non-promise return value will be ignored.
|
||||||
|
// We need to deal with some type quirks.
|
||||||
type WrappedValidator = (
|
type WrappedValidator = (
|
||||||
...args: Parameters<FormItemRuleValidator>
|
...args: FormItemRuleValidatorParams
|
||||||
) => boolean | Error | Promise<boolean | Error> | undefined
|
) => boolean | Error | Error[] | Promise<void> | undefined
|
||||||
function wrapValidator (validator: FormItemRuleValidator): WrappedValidator {
|
|
||||||
|
// wrap sync validator
|
||||||
|
function wrapValidator (
|
||||||
|
validator: FormItemRuleValidator,
|
||||||
|
async: boolean
|
||||||
|
): WrappedValidator {
|
||||||
return (...args: Parameters<FormItemRuleValidator>) => {
|
return (...args: Parameters<FormItemRuleValidator>) => {
|
||||||
try {
|
try {
|
||||||
const validateResult = validator(...args)
|
const validateResult = validator(...args)
|
||||||
if (
|
if (
|
||||||
typeof validateResult === 'boolean' ||
|
(!async &&
|
||||||
validateResult instanceof Error ||
|
(typeof validateResult === 'boolean' ||
|
||||||
validateResult?.then
|
validateResult instanceof Error ||
|
||||||
|
Array.isArray(validateResult))) || // Error[]
|
||||||
|
(validateResult as any)?.then
|
||||||
) {
|
) {
|
||||||
return validateResult
|
return validateResult as any
|
||||||
} else if (validateResult === undefined) {
|
} else if (validateResult === undefined) {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
warn(
|
warn(
|
||||||
'form-item/validate',
|
'form-item/validate',
|
||||||
`You return a ${typeof validateResult} ` +
|
`You return a ${typeof validateResult} ` +
|
||||||
'typed value in the validator method, which is not recommended. Please ' +
|
'typed value in the validator method, which is not recommended. Please use ' +
|
||||||
'use `boolean`, `Error` or `Promise` typed value instead.'
|
(async ? '`Promise`' : '`boolean`, `Error` or `Promise`') +
|
||||||
|
' typed value instead.'
|
||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -119,6 +131,8 @@ function wrapValidator (validator: FormItemRuleValidator): WrappedValidator {
|
|||||||
"`n-form` or `n-form-item` won't be called in this validation."
|
"`n-form` or `n-form-item` won't be called in this validation."
|
||||||
)
|
)
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
// If returns undefined, async-validator won't trigger callback
|
||||||
|
// so the result will be abandoned, which means not true and not false
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,10 +152,8 @@ export default defineComponent({
|
|||||||
const formItemSizeRefs = formItemSize(props)
|
const formItemSizeRefs = formItemSize(props)
|
||||||
const formItemMiscRefs = formItemMisc(props)
|
const formItemMiscRefs = formItemMisc(props)
|
||||||
const { validationErrored: validationErroredRef } = formItemMiscRefs
|
const { validationErrored: validationErroredRef } = formItemMiscRefs
|
||||||
const {
|
const { mergedRequired: mergedRequiredRef, mergedRules: mergedRulesRef } =
|
||||||
mergedRequired: mergedRequiredRef,
|
formItemRule(props)
|
||||||
mergedRules: mergedRulesRef
|
|
||||||
} = formItemRule(props)
|
|
||||||
const { mergedSize: mergedSizeRef } = formItemSizeRefs
|
const { mergedSize: mergedSizeRef } = formItemSizeRefs
|
||||||
const { mergedLabelPlacement: labelPlacementRef } = formItemMiscRefs
|
const { mergedLabelPlacement: labelPlacementRef } = formItemMiscRefs
|
||||||
const explainsRef = ref<string[]>([])
|
const explainsRef = ref<string[]>([])
|
||||||
@ -247,28 +259,31 @@ export default defineComponent({
|
|||||||
const { value: rules } = mergedRulesRef
|
const { value: rules } = mergedRulesRef
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const value = NForm ? get(NForm.model, path!, null) : undefined
|
const value = NForm ? get(NForm.model, path!, null) : undefined
|
||||||
const activeRules = (!trigger
|
const activeRules = (
|
||||||
? rules
|
!trigger
|
||||||
: rules.filter((rule) => {
|
? rules
|
||||||
// if (rule.trigger === undefined) return true
|
: rules.filter((rule) => {
|
||||||
if (Array.isArray(rule.trigger)) {
|
// if (rule.trigger === undefined) return true
|
||||||
return rule.trigger.includes(trigger)
|
if (Array.isArray(rule.trigger)) {
|
||||||
} else {
|
return rule.trigger.includes(trigger)
|
||||||
return rule.trigger === trigger
|
} else {
|
||||||
}
|
return rule.trigger === trigger
|
||||||
})
|
}
|
||||||
|
})
|
||||||
)
|
)
|
||||||
.filter(shouldRuleBeApplied)
|
.filter(shouldRuleBeApplied)
|
||||||
.map((rule) => {
|
.map((rule) => {
|
||||||
const shallowClonedRule = Object.assign({}, rule)
|
const shallowClonedRule = Object.assign({}, rule)
|
||||||
if (shallowClonedRule.validator) {
|
if (shallowClonedRule.validator) {
|
||||||
shallowClonedRule.validator = wrapValidator(
|
shallowClonedRule.validator = wrapValidator(
|
||||||
shallowClonedRule.validator
|
shallowClonedRule.validator,
|
||||||
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (shallowClonedRule.asyncValidator) {
|
if (shallowClonedRule.asyncValidator) {
|
||||||
shallowClonedRule.asyncValidator = wrapValidator(
|
shallowClonedRule.asyncValidator = wrapValidator(
|
||||||
shallowClonedRule.asyncValidator
|
shallowClonedRule.asyncValidator,
|
||||||
|
true
|
||||||
) as any
|
) as any
|
||||||
}
|
}
|
||||||
return shallowClonedRule
|
return shallowClonedRule
|
||||||
@ -279,8 +294,8 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const mergedPath = path ?? '__n_no_path__'
|
const mergedPath = path ?? '__n_no_path__'
|
||||||
const validator = new Schema({ [mergedPath]: activeRules })
|
const validator = new Schema({ [mergedPath]: activeRules as RuleItem[] })
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve) => {
|
||||||
void validator.validate(
|
void validator.validate(
|
||||||
{ [mergedPath]: value },
|
{ [mergedPath]: value },
|
||||||
options,
|
options,
|
||||||
@ -345,10 +360,8 @@ export default defineComponent({
|
|||||||
[createKey('feedbackHeight', size)]: feedbackHeight,
|
[createKey('feedbackHeight', size)]: feedbackHeight,
|
||||||
[createKey('labelPadding', direction)]: labelPadding,
|
[createKey('labelPadding', direction)]: labelPadding,
|
||||||
[createKey('labelTextAlign', direction)]: labelTextAlign,
|
[createKey('labelTextAlign', direction)]: labelTextAlign,
|
||||||
[createKey(
|
[createKey(createKey('labelFontSize', labelPlacement), size)]:
|
||||||
createKey('labelFontSize', labelPlacement),
|
labelFontSize
|
||||||
size
|
|
||||||
)]: labelFontSize
|
|
||||||
}
|
}
|
||||||
} = themeRef.value
|
} = themeRef.value
|
||||||
return {
|
return {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { InjectionKey } from '@vue/runtime-core'
|
import { InjectionKey } from 'vue'
|
||||||
import { ErrorList, RuleItem, ValidateOption } from 'async-validator'
|
import { ErrorList, RuleItem, ValidateOption } from 'async-validator'
|
||||||
import { FormSetupProps } from './Form'
|
import { FormSetupProps } from './Form'
|
||||||
|
|
||||||
@ -6,14 +6,23 @@ export interface FormRules {
|
|||||||
[path: string]: FormRules | FormItemRule | FormItemRule[]
|
[path: string]: FormRules | FormItemRule | FormItemRule[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormItemRuleValidator = (
|
export type FormItemRuleValidatorParams = Parameters<
|
||||||
...args: Parameters<RuleItem['validator'] & {}>
|
NonNullable<RuleItem['validator']>
|
||||||
) => boolean | Error | Promise<boolean> | Promise<Error> | any
|
>
|
||||||
|
|
||||||
export type FormItemRule = RuleItem & {
|
export type FormItemRuleValidator = (
|
||||||
|
...args: FormItemRuleValidatorParams
|
||||||
|
) => boolean | Error | Error[] | Promise<void> | undefined
|
||||||
|
|
||||||
|
// In src of async-validator, any non-promise of asyncValidator will be abadoned
|
||||||
|
export type FormItemRuleAsyncValidator = (
|
||||||
|
...args: FormItemRuleValidatorParams
|
||||||
|
) => Promise<void> | undefined
|
||||||
|
|
||||||
|
export type FormItemRule = Omit<RuleItem, 'validator' | 'asyncValidator'> & {
|
||||||
trigger?: ValidationTrigger | string | Array<ValidationTrigger | string>
|
trigger?: ValidationTrigger | string | Array<ValidationTrigger | string>
|
||||||
validator?: FormItemRuleValidator
|
validator?: FormItemRuleValidator
|
||||||
asyncValidator?: FormItemRuleValidator
|
asyncValidator?: FormItemRuleAsyncValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormItemValidateOptions {
|
export interface FormItemValidateOptions {
|
||||||
@ -50,9 +59,8 @@ export type FormItemRowRef = FormItemInst
|
|||||||
export type FormInjection = FormSetupProps
|
export type FormInjection = FormSetupProps
|
||||||
|
|
||||||
export const formInjectionKey: InjectionKey<FormInjection> = Symbol('form')
|
export const formInjectionKey: InjectionKey<FormInjection> = Symbol('form')
|
||||||
export const formItemInstsInjectionKey: InjectionKey<unknown> = Symbol(
|
export const formItemInstsInjectionKey: InjectionKey<unknown> =
|
||||||
'formItemInsts'
|
Symbol('formItemInsts')
|
||||||
)
|
|
||||||
|
|
||||||
export type LabelAlign = 'left' | 'center' | 'right'
|
export type LabelAlign = 'left' | 'center' | 'right'
|
||||||
export type LabelPlacement = 'left' | 'top'
|
export type LabelPlacement = 'left' | 'top'
|
||||||
|
@ -1 +1 @@
|
|||||||
export default '2.7.4'
|
export default '2.8.0'
|
||||||
|
Loading…
Reference in New Issue
Block a user