如何显式地类型ref可以附加到多个类型的元素?



我有一个组件,它根据props渲染带有文本区域或输入文本字段的JSX。我想显式地键入一个ref,以便能够附加到两种不同类型的元素(textarea或input)。我该怎么做呢?我还需要这个类型,因为当子对象接收到它时,我必须再次显式地键入props,因为我将把ref作为一个prop传递给它,以便在ref被聚焦时应用样式。

我试过了

const fieldRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);

type FieldRefType<T extends HTMLInputElement | HTMLTextAreaElement> = {
current: T | null;
};
const fieldRef =
useRef<FieldRefType<HTMLInputElement | HTMLTextAreaElement>>(null);

但是我总是得到类似于

变化的错误
Type 'RefObject<HTMLInputElement | HTMLTextAreaElement>' is not assignable to type 'LegacyRef<HTMLTextAreaElement> | undefined'.

下面是代码中相关的部分:

const FormField = ({ fieldType }: FormFieldProps): JSX.Element => {
const fieldRef = useRef<HTMLInputElement | HTMLTextAreaElement>(null);
let placeholderText: string;
switch (fieldType) {
case "Name":
placeholderText = "Enter your name";
break;
case "Email":
placeholderText = "Enter your email address";
break;
case "Subject":
placeholderText = "Enter the subject of your message";
break;
case "Message":
placeholderText = "Enter your message";
break;
default:
const _exhaustiveCheck: never = fieldType;
return _exhaustiveCheck;
}
return (
<div className={styles["label-field-container"]}>
<label className={styles["label"]} htmlFor={fieldType}>
{fieldType}
</label>
{fieldType === "Message" ? (
<textarea
className={`${styles["field"]} ${styles["field-large"]}`}
id={fieldType}
ref={fieldRef as React.RefObject<HTMLTextAreaElement>}
placeholder={placeholderText}
autoComplete="off"
required
></textarea>
) : (
<input
className={styles["field"]}
id={fieldType}
ref={fieldRef as React.RefObject<HTMLInputElement>}
type="text"
placeholder={placeholderText}
autoComplete="off"
required
></input>
)}
<FormFieldUnderline />
</div>
);
};
编辑:做ref={fieldRef as React.RefObject<HTMLTextAreaElement>}

工作,但有些东西告诉我这是一个坏主意,在这里使用类型断言。有没有更好的办法?编辑2:使用交叉点作为const fieldRef = useRef<HTMLInputElement & HTMLTextAreaElement>(null);将工作,因为TS知道不会有任何类型错误。这将限制变量只能访问这两种类型的属性。

问题如下:typescript期望信息从您的组件流向inputtextarea,而refs则相反:这些组件获得对对象的引用,它们将修改该对象并向您的组件提供信息。想象一下,如果fieldRef不是一个ref,而只是一个对象,您将一些信息传递给组件<Foo info={fieldRef} />来处理。想象一下,Fooinfo属性类型被设置为{ current: HTMLInputElement },因为Foo只知道如何与HTMLInputElement对象一起工作,所以如果你传递{ current: HTMLInputElement | HTMLTextareaElement }类型的对象就会出现错误:这个对象的目的是给Foo提供信息,而Foo不知道如何与HTMLTextareaElements一起工作。Refs有不同的目的,但是没有办法告诉typescript"嘿,这个对象的目的不是传递信息给input,而是让input修改它"。

所以要输入这个,你必须使用断言,或者传递函数ref到input而不是ref对象。这种方式是明确的:你传递一个函数给inputtextarea,他们将调用HTMLInputElementHTMLTextareaElement,这个函数知道如何使用这两个,所以没有错误:

const fieldRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);
const setRef = (e: HTMLInputElement | HTMLTextAreaElement) => fieldRef.current = e;
<input ref={setRef} />
<textarea ref={setRef} />

或者直接内联

const fieldRef = useRef<HTMLInputElement | HTMLTextAreaElement | null>(null);
<input ref={e => fieldRef.current = e} />
<textarea ref={e => fieldRef.current = e} />

相关内容

  • 没有找到相关文章

最新更新