Reactjs 如何正确推断反应道具从作为道具与通用重载
我试图制作一个通用组件,它可以根据Reactjs 如何正确推断反应道具从作为道具与通用重载,reactjs,typescript,generics,Reactjs,Typescript,Generics,我试图制作一个通用组件,它可以根据作为道具推断道具类型 我发现以下类型对于{as?:keyof JSX.intrinsiceelements}来说可以正常工作: import React from 'react'; interface Comp<TComponentProps extends {}> { (props: TComponentProps & { as?: undefined }): React.ReactElement | null; <
作为道具推断道具类型
我发现以下类型对于{as?:keyof JSX.intrinsiceelements}
来说可以正常工作:
import React from 'react';
interface Comp<TComponentProps extends {}> {
(props: TComponentProps & { as?: undefined }): React.ReactElement | null;
<
TProps extends { as: keyof JSX.IntrinsicElements },
P = TProps extends { as: infer C }
? C extends keyof JSX.IntrinsicElements
? JSX.IntrinsicElements[C] & TComponentProps
: TComponentProps
: TComponentProps
>(
props: TProps & P,
): React.ReactElement | null;
}
declare const A: Comp<{}>;
declare const B: Comp<{ test: boolean }>;
declare const C: React.FunctionComponent<{ fn: boolean }>;
declare const D: React.ComponentClass<{ cls: boolean }>;
<A />; // valid
<B />; // invalid, test is missing
<B test />; // valid
<A as="img" src={10} />; // invalid, src cannot be a number
<A as="img" src="" />; // valid
/*
<A as={B} />; // invalid, test is missing
<A as={B} test />; // valid
<A as={C} />; // invalid, fn is missing
<A as={C} fn />; // valid
<A as={D} />; // invalid, cls is missing
<A as={D} cls />; // valid
*/
我没有得到预期的结果,但所有行都通过了类型检查
我尝试了多种可能的解决方案,例如:
import React from 'react';
interface Comp<TComponentProps extends {}> {
<
TProps extends {
as?: keyof JSX.IntrinsicElements;
},
P = TProps extends { as?: infer C }
? C extends undefined | unknown
? {}
: C extends keyof JSX.IntrinsicElements
? JSX.IntrinsicElements[C]
: {}
: {}
>(
props: TProps & TComponentProps & P,
): React.ReactElement | null;
<
TProps extends {
as?: React.JSXElementConstructor<any>;
},
P = TProps extends { as: React.JSXElementConstructor<infer P> } ? P : {}
>(
props: TProps & TComponentProps & P,
): React.ReactElement | null;
}
declare const A: Comp<{}>;
declare const B: Comp<{ test: boolean }>;
declare const C: React.FunctionComponent<{ fn: boolean }>;
declare const D: React.ComponentClass<{ cls: boolean }>;
<A />; // valid
<B />; // invalid, test is missing
<B test />; // valid
<A as="img" src={10} />; // invalid, src cannot be a number
<A as="img" src="" />; // valid
<A as={B} />; // invalid, test is missing
<A as={B} test />; // valid
<A as={C} />; // invalid, fn is missing
<A as={C} fn />; // valid
<A as={D} />; // invalid, cls is missing
<A as={D} cls />; // valid
从“React”导入React;
接口组件{
<
TProps扩展{
as?:JSX.intrinsiceelements的键;
},
P=TProps扩展{as?:推断C}
?C扩展未定义|未知
? {}
:C扩展JSX.intrinsiceelements的键
?JSX.本质元素[C]
: {}
: {}
>(
道具:TProps&t组件道具&P,
):React.ReactElement | null;
<
TProps扩展{
as?:React.JSXElementConstructor
但是运气不好。有人能给我指出正确的打字方向吗?好的,我通过以下打字解决了这个问题:
type HTMLELProps<
TElement extends keyof JSX.IntrinsicElements,
TComponentProps extends {}
> = { as: TElement } & JSX.IntrinsicElements[TElement] &
TComponentProps &
StyleProps &
React.RefAttributes<any>;
export interface Component<TComponentProps extends {}> {
displayName?: string;
// as component (as component type)
<P>(
props: { as: React.ComponentType<P> } & P &
TComponentProps &
StyleProps &
React.RefAttributes<any>,
): React.ReactElement | null;
// HTML (as="a")
(props: HTMLELProps<'a', TComponentProps>): React.ReactElement | null;
(props: HTMLELProps<'abbr', TComponentProps>): React.ReactElement | null;
// ... rest
// without as prop
(props: TComponentProps & StyleProps): React.ReactElement | null;
}
键入HTMLELProps<
TElement扩展了JSX.intrinsiceElements的功能,
TComponentProps扩展了{}
>={as:TElement}&JSX.intrinsiceelements[TElement]&
t组件支柱&
样式道具&
React.RefAttributes;
导出接口组件{
displayName?:字符串;
//作为组件(作为组件类型)
(
支柱:{as:React.ComponentType
}&P&
t组件支柱&
样式道具&
React.RefAttributes,
):React.ReactElement | null;
//HTML(as=“a”)
(props:htmleprops):React.ReactElement | null;
(props:htmleprops):React.ReactElement | null;
//……休息
//没有支柱
(props:TComponentProps和StyleProps):React.ReactElement | null;
}
基本上,问题是typescript很难根据泛型约束推断道具。现在,即使在Visual Studio代码中使用autocomplete,它也能正常工作。问题是,类型现在有点慢。我不知道为什么,我希望您能提供帮助
type HTMLELProps<
TElement extends keyof JSX.IntrinsicElements,
TComponentProps extends {}
> = { as: TElement } & JSX.IntrinsicElements[TElement] &
TComponentProps &
StyleProps &
React.RefAttributes<any>;
export interface Component<TComponentProps extends {}> {
displayName?: string;
// as component (as component type)
<P>(
props: { as: React.ComponentType<P> } & P &
TComponentProps &
StyleProps &
React.RefAttributes<any>,
): React.ReactElement | null;
// HTML (as="a")
(props: HTMLELProps<'a', TComponentProps>): React.ReactElement | null;
(props: HTMLELProps<'abbr', TComponentProps>): React.ReactElement | null;
// ... rest
// without as prop
(props: TComponentProps & StyleProps): React.ReactElement | null;
}