最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

reactjs - TypeScript throws Type 'KeyboardEvent | FocusEvent<HTMLInputElement, Element>' is not as

programmeradmin3浏览0评论

I have FormContextInput type and reusable Input component like the below:

export type FormContextInput  = {
  name:string,
  eventType: "onBlur" | "onKeyDown" | "onClick",
  validate: (event:React.FocusEvent<HTMLInputElement> | KeyboardEvent) => void | Promise<void>,
} & React.InputHTMLAttributes<HTMLInputElement>;

the Input component accepts a validate function. and I'm reusing it inside two different components A and B. the validation function of A triggers on onBlur, and the B's validation triggers on onKeyDown

Input code:

export default function Input({name, eventType, validate, ...props}:FormContextInput) {

  async function handleValidate(event:React.FocusEvent<HTMLInputElement> | KeyboardEvent) {
    try {
      await Promise.resolve(validate(event));
      setError("");
    } catch (error) {
      setError((error as Error).message);
    }

  }

  return (
      <input name={name} {...props}
      {...(eventType === "onBlur" && {onBlur:handleValidate})}
      {...(eventType === "onKeyDown" && {onKeyDown:handleValidate})}
      />
  )
}

A validation function :

function validation(event: React.FocusEvent<HTMLInputElement>) {}

B validation function:

function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {}

but I'm getting three errors on all components. A and B have an error line where I'm passing their validation function to the Input as a prop: A error:

Type '(event: FocusEvent<HTMLInputElement, Element>) => void' is not assignable to type '(event: FocusEvent<HTMLInputElement, Element> | KeyboardEvent) => void | Promise<void>'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'FocusEvent<HTMLInputElement, Element> | KeyboardEvent' is not assignable to type 'FocusEvent<HTMLInputElement, Element>'.
      Type 'KeyboardEvent' is missing the following properties from type 'FocusEvent<HTMLInputElement, Element>': relatedTarget, nativeEvent, isDefaultPrevented, isPropagationStopped, persist

B error:

Type '(event: KeyboardEvent<HTMLInputElement>) => void' is not assignable to type '(event: FocusEvent<HTMLInputElement, Element> | KeyboardEvent) => void | Promise<void>'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'FocusEvent<HTMLInputElement, Element> | KeyboardEvent' is not assignable to type 'KeyboardEvent<HTMLInputElement>'.
      Type 'FocusEvent<HTMLInputElement, Element>' is missing the following properties from type 'KeyboardEvent<HTMLInputElement>': altKey, charCode, ctrlKey, code, and 11 more

each one of them is complaining about the other event's type it seems to me like TypeScript ignores the | between the two types and doesn't recognise them as separate things!

Input error line is under the <input/> tag:

No overload matches this call.

I tried to change the type definition to React.SyntheticEvent but it also throws errors since it too loose and I'll have to narrow the event types. the only solution that "fixes" this is to use any but that has it's problems too.

I have FormContextInput type and reusable Input component like the below:

export type FormContextInput  = {
  name:string,
  eventType: "onBlur" | "onKeyDown" | "onClick",
  validate: (event:React.FocusEvent<HTMLInputElement> | KeyboardEvent) => void | Promise<void>,
} & React.InputHTMLAttributes<HTMLInputElement>;

the Input component accepts a validate function. and I'm reusing it inside two different components A and B. the validation function of A triggers on onBlur, and the B's validation triggers on onKeyDown

Input code:

export default function Input({name, eventType, validate, ...props}:FormContextInput) {

  async function handleValidate(event:React.FocusEvent<HTMLInputElement> | KeyboardEvent) {
    try {
      await Promise.resolve(validate(event));
      setError("");
    } catch (error) {
      setError((error as Error).message);
    }

  }

  return (
      <input name={name} {...props}
      {...(eventType === "onBlur" && {onBlur:handleValidate})}
      {...(eventType === "onKeyDown" && {onKeyDown:handleValidate})}
      />
  )
}

A validation function :

function validation(event: React.FocusEvent<HTMLInputElement>) {}

B validation function:

function handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {}

but I'm getting three errors on all components. A and B have an error line where I'm passing their validation function to the Input as a prop: A error:

Type '(event: FocusEvent<HTMLInputElement, Element>) => void' is not assignable to type '(event: FocusEvent<HTMLInputElement, Element> | KeyboardEvent) => void | Promise<void>'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'FocusEvent<HTMLInputElement, Element> | KeyboardEvent' is not assignable to type 'FocusEvent<HTMLInputElement, Element>'.
      Type 'KeyboardEvent' is missing the following properties from type 'FocusEvent<HTMLInputElement, Element>': relatedTarget, nativeEvent, isDefaultPrevented, isPropagationStopped, persist

B error:

Type '(event: KeyboardEvent<HTMLInputElement>) => void' is not assignable to type '(event: FocusEvent<HTMLInputElement, Element> | KeyboardEvent) => void | Promise<void>'.
  Types of parameters 'event' and 'event' are incompatible.
    Type 'FocusEvent<HTMLInputElement, Element> | KeyboardEvent' is not assignable to type 'KeyboardEvent<HTMLInputElement>'.
      Type 'FocusEvent<HTMLInputElement, Element>' is missing the following properties from type 'KeyboardEvent<HTMLInputElement>': altKey, charCode, ctrlKey, code, and 11 more

each one of them is complaining about the other event's type it seems to me like TypeScript ignores the | between the two types and doesn't recognise them as separate things!

Input error line is under the <input/> tag:

No overload matches this call.

I tried to change the type definition to React.SyntheticEvent but it also throws errors since it too loose and I'll have to narrow the event types. the only solution that "fixes" this is to use any but that has it's problems too.

Share Improve this question edited Mar 16 at 18:38 Marya asked Mar 16 at 18:09 MaryaMarya 1708 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

The issue is that TypeScript expects the validate function to handle both FocusEvent and KeyboardEvent, but the validation functions in components A and B are specific to one type.

Solution:

Use a type guard in handleValidate to differentiate between FocusEvent and KeyboardEvent:

async function handleValidate(event: React.FocusEvent<HTMLInputElement> | React.KeyboardEvent<HTMLInputElement>) {
  try {
    if ("relatedTarget" in event) {
      await validate(event as React.FocusEvent<HTMLInputElement>);
    } else {
      await validate(event as React.KeyboardEvent<HTMLInputElement>);
    }
    setError("");
  } catch (error) {
    setError((error as Error).message);
  }
}

This resolves the type conflict by narrowing the event type.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论