3

我使用的技术是 react、typescript 和 styled-components。我正在尝试创建选择组件以便在 React Hook Form 中使用它。起初,看起来一切都是正确的,但我从打字稿中得到一个错误说:

没有重载匹配此调用。重载 1 of 2, '(props: Pick<Pick<Pick<DetailedHTMLProps<SelectHTMLAttributes, HTMLSelectElement>, "form" | ... 262 更多 ... | "onTransitionEndCapture"> & { ...; } & ISelectProps, " form" | ... 264 更多 ... | "options"> & Partial<...>, "form" | ... 264 更多 ... | "options"> & { ...; } & { ...; }): ReactElement<...>',给出了以下错误。类型“ForwardedRef”不可分配给类型“RefObject | (RefObject & ((instance: HTMLSelectElement | null) => void)) | (((实例:HTMLSelectElement | null) => void) & RefObject<...>) | ((((实例:HTMLSelectElement | null)=> void)&(((实例:HTMLSelectElement | null)=> void))| 空 | 不明确的'。类型“MutableRefObject”不可分配给类型“RefObject | (RefObject & ((instance: HTMLSelectElement | null) => void)) | (((实例:HTMLSelectElement | null) => void) & RefObject<...>) | ((((实例:HTMLSelectElement | null)=> void)&(((实例:HTMLSelectElement | null)=> void))| 空 | 不明确的'。类型 'MutableRefObject' 不可分配给类型 '((instance: HTMLSelectElement | null) => void) & RefObject'。类型“MutableRefObject”不可分配给类型“(实例:HTMLSelectElement | null)=> void”。类型“MutableRefObject”不匹配签名“(实例:HTMLSelectElement | null):void”。HTML选择元素 | 空)=> 无效))| (((实例:HTMLSelectElement | null) => void) & RefObject<...>) | ((((实例:HTMLSelectElement | null)=> void)&(((实例:HTMLSelectElement | null)=> void))| 空 | 不明确的'。类型 'MutableRefObject' 不可分配给类型 '((instance: HTMLSelectElement | null) => void) & RefObject'。类型“MutableRefObject”不可分配给类型“(实例:HTMLSelectElement | null)=> void”。类型“MutableRefObject”不匹配签名“(实例:HTMLSelectElement | null):void”。HTML选择元素 | 空)=> 无效))| (((实例:HTMLSelectElement | null) => void) & RefObject<...>) | ((((实例:HTMLSelectElement | null)=> void)&(((实例:HTMLSelectElement | null)=> void))| 空 | 不明确的'。类型 'MutableRefObject' 不可分配给类型 '((instance: HTMLSelectElement | null) => void) & RefObject'。类型“MutableRefObject”不可分配给类型“(实例:HTMLSelectElement | null)=> void”。类型“MutableRefObject”不匹配签名“(实例:HTMLSelectElement | null):void”。类型 'MutableRefObject' 不可分配给类型 '((instance: HTMLSelectElement | null) => void) & RefObject'。类型“MutableRefObject”不可分配给类型“(实例:HTMLSelectElement | null)=> void”。类型“MutableRefObject”不匹配签名“(实例:HTMLSelectElement | null):void”。类型 'MutableRefObject' 不可分配给类型 '((instance: HTMLSelectElement | null) => void) & RefObject'。类型“MutableRefObject”不可分配给类型“(实例:HTMLSelectElement | null)=> void”。类型“MutableRefObject”不匹配签名“(实例:HTMLSelectElement | null):void”。

这是我的代码:

import React, { forwardRef } from "react";
import styled from "styled-components";
import arrow from "../assets/svg/select_arrow.svg";

interface ISelectProps {
  options?: { name: string; value: string | number }[];
  name: string;
  ref?:
    | ((instance: HTMLSelectElement | null) => void)
    | React.RefObject<HTMLSelectElement>
    | null
    | undefined;
}

const SelectContainer = styled.div`
  display: flex;
  align-items: center;
  width: 100%;
  position: relative;
`;

const StyledSelect = styled.select<ISelectProps>`
  width: 100%;
  height: 30px;
  padding: 0 10px;
  background: ${({ theme }) => theme.colors.transparentButton};
  color: white;
  border: 1px solid white;
  border-radius: ${({ theme }) => theme.borderRadius};
  font-size: 14px;
  -moz-appearance: none; /* Firefox */
  -webkit-appearance: none; /* Safari and Chrome */
  appearance: none;
  &:focus,
  &:active {
    outline: none;
  }
`;

const StyledArrow = styled.img`
  position: absolute;
  right: 10px;
  padding: inherit;
`;

const Select = forwardRef(({ options, name }: ISelectProps, ref) => {
  return (
    <>
      <SelectContainer>
        <StyledSelect name={name} ref={ref}>
          {options?.map((op) => (
            <option value={op.value}>{op.name}</option>
          ))}
        </StyledSelect>
        <StyledArrow src={arrow} />
      </SelectContainer>
    </>
  );
});

export default Select;

codeandbox.io/s/eager-hertz-opbsi?file=/src/select.tsx

我究竟做错了什么?提前感谢所有有用的答案!

4

2 回答 2

2

首先,ref在这种情况下不是道具的一部分。您应该提供两个通用参数forwardRef来帮助 TS 缩小类型。

是什么ref?它只是 HTML 元素

import React, { forwardRef } from "react";
import styled from "styled-components";

interface ISelectProps {
  options?: { name: string; value: string | number }[];
  name: string;

}

const SelectContainer = styled.div`
  display: flex;
  align-items: center;
  width: 100%;
  position: relative;
`;

const StyledSelect = styled.select<ISelectProps>`
  width: 100%;
  height: 30px;
  padding: 0 10px;
  background: ${({ theme }) => theme.colors.transparentButton};
  color: white;
  border: 1px solid white;
  border-radius: ${({ theme }) => theme.borderRadius};
  font-size: 14px;
  -moz-appearance: none; /* Firefox */
  -webkit-appearance: none; /* Safari and Chrome */
  appearance: none;
  &:focus,
  &:active {
    outline: none;
  }
`;

const StyledArrow = styled.img`
  position: absolute;
  right: 10px;
  padding: inherit;
`;

const Select = forwardRef<HTMLSelectElement, ISelectProps>(({ options, name }, ref) => {
  return (
    <>
      <SelectContainer>
        <StyledSelect name={name} ref={ref}>
          {options?.map((op) => (
            <option value={op.value}>{op.name}</option>
          ))}
        </StyledSelect>
      </SelectContainer>
    </>
  );
});

export default Select;

游乐场链接

于 2021-02-22T09:04:07.147 回答
0

您从未输入过ref对象,请查看React TypeScript Cheatsheet -forwardRef中的示例。

// T typing the ref
forwardRef<T, P = {}>(...)

// Full typing signature
function forwardRef<T, P = {}>(render: ForwardRefRenderFunction<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;

// BAD - ref object untyped
const Select = forwardRef(({ options, name }: ISelectProps, ref) => {...}

// GOOD - ref object typed
const Select = forwardRef<HTMLSelectElement, ISelectProps>(
  ({ options, name }, ref) => {...}
);

https://codesandbox.io/s/hungry-architecture-7gsnp?file=/src/select.tsx:665-1038

于 2021-02-22T09:18:48.037 回答