首页 > 解决方案 > 打字稿 + 使用参考: X 型不能分配给 Y 型

问题描述

这个简单的组件:

const Editable = ({multiline}: { multiline: boolean }) => {
    const ref = useRef<HTMLInputElement|HTMLTextAreaElement>(null);
    return <div>
        {multiline ? <textarea ref={ref}/> : <input ref={ref}/>}
    </div>
}

有以下 TypeScript 错误:

Error:(7, 32) TS2322: Type 'RefObject<HTMLInputElement | HTMLTextAreaElement>' is not assignable to type 'string | ((instance: HTMLTextAreaElement | null) => void) | RefObject<HTMLTextAreaElement> | null | undefined'.
  Type 'RefObject<HTMLInputElement | HTMLTextAreaElement>' is not assignable to type 'RefObject<HTMLTextAreaElement>'.
    Type 'HTMLInputElement | HTMLTextAreaElement' is not assignable to type 'HTMLTextAreaElement'.
      Type 'HTMLInputElement' is missing the following properties from type 'HTMLTextAreaElement': cols, rows, textLength, wrap
Error:(7, 53) TS2322: Type 'RefObject<HTMLInputElement | HTMLTextAreaElement>' is not assignable to type 'string | ((instance: HTMLInputElement | null) => void) | RefObject<HTMLInputElement> | null | undefined'.
  Type 'RefObject<HTMLInputElement | HTMLTextAreaElement>' is not assignable to type 'RefObject<HTMLInputElement>'.
    Type 'HTMLInputElement | HTMLTextAreaElement' is not assignable to type 'HTMLInputElement'.
      Type 'HTMLTextAreaElement' is missing the following properties from type 'HTMLInputElement': accept, align, alt, checked, and 23 more.

可以使用以下行忽略错误:

const ref = useRef<any>(null);

如何useRef使用正确的类型并且没有错误?

标签: reactjstypescript

解决方案


解决方案 1:类型断言

const ref = useRef<HTMLInputElement | HTMLTextAreaElement>(null);
return (
    <div>
        {multiline ? <textarea ref={ref as React.RefObject<HTMLTextAreaElement>}/>:
            <input ref={ref as React.RefObject<HTMLInputElement>} />}
    </div>
)

<textarea ... />需要一个refHTMLTextAreaElementHTMLTextAreaElement包含与不同的属性 ,因此无法将超类型分配给其中一个节点。类型断言在这里非常好。优点:我们被迫以类型安全的方式缩小范围。缺点:类型断言有点冗长。 HTMLInputElement HTMLTextAreaElement | HTMLInputElementref

解决方案 2:ref 的交集类型

const ref = useRef<HTMLInputElement & HTMLTextAreaElement>(null);
return (
    <div>
        {multiline ? <textarea ref={ref } /> :
            <input ref={ref} />}
    </div>
)

这有效,因为HTMLInputElement并且HTMLTextAreaElement没有冲突的属性类型(否则会导致never)。优点:更紧凑的代码。缺点:确保之前缩小元素。例如,您可能能够调用以下代码来HTMLInputElement导致运行时错误:

ref.current && ref.current.cols // input does not have cols

操场


推荐阅读