代码之家  ›  专栏  ›  技术社区  ›  Udi

TypeScript+useRef:Type…不可分配给Type

  •  1
  • Udi  · 技术社区  · 5 年前

    这个简单的组件:

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

    存在以下类型脚本错误:

    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 是否与正确的类型一起使用且没有错误?

    1 回复  |  直到 5 年前
        1
  •  4
  •   ford04    5 年前

    解决方案1: Type assertion

    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 ... /> 期待一个 ref 这需要 HTMLTextAreaElement . HtmlTextArea元素 包含 different properties than HTMLInputElement ,所以 supertype HTMLTextAreaElement | HTMLInputElement 无法分配给 节点的数量。在这里,类型断言非常好。优点:我们被迫缩小范围 ref 以安全的方式。缺点:类型断言有点冗长。

    解决方案2: Intersection type 参考

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

    这是有效的,就像 HTMLInputElement HtmlTextArea元素 不要有冲突的属性类型(否则会导致 never )优点:代码更紧凑。缺点:一定要缩小之前的元素。例如,您可以调用以下代码 HTMLInputElement 导致运行时错误:

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

    Playground