使用Typescript进行反应—使用React.forwardRef时的泛型
我正在尝试创建一个通用组件,用户可以在其中将自定义传递OptionType
给组件以一路进行类型检查。此组件还需要一个React.forwardRef
。
我可以在没有forwardRef的情况下使其正常工作。有任何想法吗?代码如下:
export interface Option<OptionValueType = unknown> { value: OptionValueType;
label: string;
}
interface WithoutForwardRefProps<OptionType> {
onChange: (option: OptionType) => void;
options: OptionType[];
}
export const WithoutForwardRef = <OptionType extends Option>(
props: WithoutForwardRefProps<OptionType>,
) => {
const { options, onChange } = props;
return (
<div>
{options.map((opt) => {
return (
<div
onClick={() => {
onChange(opt);
}}
>
{opt.label}
</div>
);
})}
</div>
);
};
import { Option } from './WithoutForwardRef';interface WithForwardRefProps<OptionType> {
onChange: (option: OptionType) => void;
options: OptionType[];
}
export const WithForwardRef = React.forwardRef(
<OptionType extends Option>(
props: WithForwardRefProps<OptionType>,
ref?: React.Ref<HTMLDivElement>,
) => {
const { options, onChange } = props;
return (
<div>
{options.map((opt) => {
return (
<div
onClick={() => {
onChange(opt);
}}
>
{opt.label}
</div>
);
})}
</div>
);
},
);
import { WithoutForwardRef, Option } from './WithoutForwardRef';import { WithForwardRef } from './WithForwardRef';
interface CustomOption extends Option<number> {
action: (value: number) => void;
}
const App: React.FC = () => {
return (
<div>
<h3>Without Forward Ref</h3>
<h4>Basic</h4>
<WithoutForwardRef
options={[{ value: 'test', label: 'Test' }, { value: 1, label: 'Test Two' }]}
onChange={(option) => {
// Does type inference on the type of value in the options
console.log('BASIC', option);
}}
/>
<h4>Custom</h4>
<WithoutForwardRef<CustomOption>
options={[
{
value: 1,
label: 'Test',
action: (value) => {
console.log('ACTION', value);
},
},
]}
onChange={(option) => {
// Intellisense works here
option.action(option.value);
}}
/>
<h3>With Forward Ref</h3>
<h4>Basic</h4>
<WithForwardRef
options={[{ value: 'test', label: 'Test' }, { value: 1, label: 'Test Two' }]}
onChange={(option) => {
// Does type inference on the type of value in the options
console.log('BASIC', option);
}}
/>
<h4>Custom (WitForwardRef is not generic here)</h4>
<WithForwardRef<CustomOption>
options={[
{
value: 1,
label: 'Test',
action: (value) => {
console.log('ACTION', value);
},
},
]}
onChange={(option) => {
// Intellisense SHOULD works here
option.action(option.value);
}}
/>
</div>
);
};
在中App.tsx
,它表示该WithForwardRef
组件不是通用的。有没有办法做到这一点?
回购示例:https :
//github.com/jgodi/generics-with-forward-
ref
谢谢!
回答:
创建通用组件作为输出React.forwardRef
是不能直接1(见底部进一步信息)。不过,还有其他选择-让我们简化示例以进行说明:
type Option<O = unknown> = { value: O;
label: string;
}
type Props<T extends Option<unknown>> = { options: T[] }
const options = [
{ value: 1, label: "la1", flag: true },
{ value: 2, label: "la2", flag: false }
] // just some options data
1.投放
// Given input comp for React.forwardRefconst FRefInputComp = <T extends Option>(props: Props<T>, ref: Ref<HTMLDivElement>) =>
<div ref={ref}> {props.options.map(o => <p>{o.label}</p>)} </div>
// Cast the output
const FRefOutputComp1 = React.forwardRef(FRefInputComp) as
<T extends Option>(p: Props<T> & { ref?: Ref<HTMLDivElement> }) => ReactElement
const Usage11 = () => <FRefOutputComp1 options={options} ref={myRef} />
// options has type { value: number; label: string; flag: boolean; }[]
// , so we have made FRefOutputComp generic!
forwardRef
之所以有效,是因为原则上返回类型是一个普通函数。我们只需要一个通用函数类型形状。您可以使用其他类型来简化断言:
type ForwardRefFn<R> = <P = {}>(p: P & React.RefAttributes<R>) => ReactElement | null// RefAttributes is built-in with ref and key props defined
const Comp12 = React.forwardRef(FRefInputComp) as ForwardRefFn<HTMLDivElement>
const Usage12 = () => <Comp12 options={options} ref={myRef} />
2.包起来
const FRefOutputComp2 = React.forwardRef(FRefInputComp)// T is replaced by its constraint Option<unknown> in FRefOutputComp2
export const Wrapper = <T extends Option>({myRef, ...rest}:
Props<T> & {myRef: React.Ref<HTMLDivElement>}) => <FRefOutputComp2 {...rest} ref={myRef} />
const Usage2 = () => <Wrapper options={options} myRef={myRef} />
3.忽略它(使用自定义ref prop)
这是我最喜欢的-最简单的替代方法,在React中是合法的方法,并且不使用forwardRef
。
const Comp3 = <T extends Option>(props: Props<T> & { myRef: Ref<HTMLDivElement> }) => <div ref={myRef}> {props.options.map(o => <p>{o.label}</p>)} </div>
const Usage3 = () => <Comp3 options={options} myRef={myRef} />
1的类型声明的React.forwardRef
为:
function forwardRef<T, P = {}>(render: ForwardRefRenderFunction<T, P>): ...
因此,它采用了类似组件的通用接口,其类型参数T,P
必须 是具体的。换句话说:ForwardRefRenderFunction
是 不是 一个普通的
函数
声明,所以高阶函数类型推断 不能
在调用函数传播自由型参数React.forwardRef
。
操场
以上是 使用Typescript进行反应—使用React.forwardRef时的泛型 的全部内容, 来源链接: utcz.com/qa/435277.html