React 无法识别联合类型
union types not being recognised in React
我有这些类型:
export enum LayersItemOptionsEnum {
OPERATOR,
HEADER,
}
type sharedTypes = {
children: string | ReactElement;
};
type LayersItemStatic = sharedTypes & {
label: string;
option: LayersItemOptionsEnum;
};
type LayersItemDynamic = sharedTypes & {
currentLayer: LayersElement;
};
export type LayersItemProps = (LayersItemDynamic | LayersItemStatic) & sharedTypes;
我正在尝试像这样使用它们:
export const LayersItem: FC<LayersItemProps> = (props): ReactElement => {
const isHeader = props.option === LayersItemOptionsEnum.HEADER;
const { isInEditMode } = useAppSelector((state) => state.editMode);
const shouldRenderOptions = isInEditMode && !isHeader;
const { selectedState } = useAppSelector((state) => state);
const states = useAppSelector((state) => state.statesData.elements);
return (
<StyledLayersItem header={isHeader}>
<Row>
<Col span={8} offset={1 /* todo: add offset dynamically */}>
<h1>{props.label ? props.label : props.currentLayer.name}</h1>
</Col>
<Col span={8} offset={4}>
{shouldRenderOptions ? (
<Form.Item className="form-item" initialValue={props.children}>
<Select>
{generateOptions({ selectedState, states, props.currentLayer }).map((value) => {
return (
<Select.Option value={value.id} key={value.id}>
{value.name}
</Select.Option>
);
})}
</Select>
</Form.Item>
) : (
<>{props.children}</>
)}
</Col>
</Row>
</StyledLayersItem>
);
};
但是我收到了这样的错误:
Property 'label' does not exist on type 'PropsWithChildren<LayersItemProps>'.
Property 'label' does not exist on type 'sharedTypes & { currentLayer: LayersElement; } & { children?: ReactNode; }'.
除了 props.children
之外的每个 props.
。就像它没有看到类型的联合。还是我误会了什么?
基本上,如果道具有label
,或option
,我希望props
是LayersItemStatic & shared Types
类型,如果有currentLayer
在 props
中,我希望它们是 LayersItemDynamic & sharedTypes
.
类型
那么我在这里错过了什么?
我正在努力实现这样的目标:
type SharedType = SharedDisplayAndEditTypes & {
required?: boolean;
validationMessage: string;
name: string;
};
type TextType = {
type: 'text';
children: string;
};
type NumberType = {
type: 'number';
children: number;
};
type InputType = TextType | NumberType;
type DropdownType = {
type: 'dropdown';
options: string[];
children: string;
};
type ColorType = {
type: 'color';
defaultValue: string;
};
export type DetailsItemEditProps = (DropdownType | InputType | ColorType) & SharedType;
考虑这个例子:
import { ReactElement } from 'react'
type LayersElement = {
tag: 'LayersElement'
}
export enum LayersItemOptionsEnum {
OPERATOR,
HEADER,
}
type sharedTypes = {
children: string | ReactElement;
};
type LayersItemStatic = sharedTypes & {
label: string;
option: LayersItemOptionsEnum;
};
type LayersItemDynamic = sharedTypes & {
currentLayer: LayersElement;
};
export type LayersItemProps = (LayersItemDynamic | LayersItemStatic) & sharedTypes;
declare var props: LayersItemProps;
props.children // ok
只允许使用 children
道具,因为它是联合的每个元素的公共道具。
由于没有人知道实际上允许联合的哪个元素,TS 决定只允许您使用对联合的每个元素都是安全的属性。
考虑这个较小的例子:
type LayersItemStatic = {
label: string;
option: string;
};
type LayersItemDynamic = {
currentLayer: string;
};
export type LayersItemProps = LayersItemDynamic | LayersItemStatic
declare var props: LayersItemProps;
因为没有常用道具,所以你不能使用任何道具。
我认为这种类型不正确:
export type LayersItemProps = (LayersItemDynamic | LayersItemStatic) & sharedTypes
由于LayersItemDynamic | LayersItemStatic
缩减为{}
而LayersItemProps
基本等于sharedTypes
.
因为您已经将 & sharedType
添加到两个 LayersItemDynamic | LayersItemStatic
中,您需要重写您的类型 LayersItemProps
如下:
import { ReactElement } from 'react'
type LayersElement = {
tag: 'LayersElement'
}
export enum LayersItemOptionsEnum {
OPERATOR,
HEADER,
}
type sharedTypes = {
children: string | ReactElement;
};
type LayersItemStatic = sharedTypes & {
label: string;
option: LayersItemOptionsEnum;
};
type LayersItemDynamic = sharedTypes & {
currentLayer: LayersElement;
};
const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
: obj is Obj & Record<Prop, unknown> =>
Object.prototype.hasOwnProperty.call(obj, prop);
export type LayersItemProps = LayersItemDynamic | LayersItemStatic
const isDynamic = (props: LayersItemProps): props is LayersItemDynamic => hasProperty(props, 'currentLayer')
const isStatic = (props: LayersItemProps): props is LayersItemStatic => hasProperty(props, 'label')
declare var props: LayersItemProps;
if (isDynamic(props)) {
props.currentLayer // ok
}
if (isStatic(props)) {
props.label // ok
props.option // ok
}
我有这些类型:
export enum LayersItemOptionsEnum {
OPERATOR,
HEADER,
}
type sharedTypes = {
children: string | ReactElement;
};
type LayersItemStatic = sharedTypes & {
label: string;
option: LayersItemOptionsEnum;
};
type LayersItemDynamic = sharedTypes & {
currentLayer: LayersElement;
};
export type LayersItemProps = (LayersItemDynamic | LayersItemStatic) & sharedTypes;
我正在尝试像这样使用它们:
export const LayersItem: FC<LayersItemProps> = (props): ReactElement => {
const isHeader = props.option === LayersItemOptionsEnum.HEADER;
const { isInEditMode } = useAppSelector((state) => state.editMode);
const shouldRenderOptions = isInEditMode && !isHeader;
const { selectedState } = useAppSelector((state) => state);
const states = useAppSelector((state) => state.statesData.elements);
return (
<StyledLayersItem header={isHeader}>
<Row>
<Col span={8} offset={1 /* todo: add offset dynamically */}>
<h1>{props.label ? props.label : props.currentLayer.name}</h1>
</Col>
<Col span={8} offset={4}>
{shouldRenderOptions ? (
<Form.Item className="form-item" initialValue={props.children}>
<Select>
{generateOptions({ selectedState, states, props.currentLayer }).map((value) => {
return (
<Select.Option value={value.id} key={value.id}>
{value.name}
</Select.Option>
);
})}
</Select>
</Form.Item>
) : (
<>{props.children}</>
)}
</Col>
</Row>
</StyledLayersItem>
);
};
但是我收到了这样的错误:
Property 'label' does not exist on type 'PropsWithChildren<LayersItemProps>'.
Property 'label' does not exist on type 'sharedTypes & { currentLayer: LayersElement; } & { children?: ReactNode; }'.
除了 props.children
之外的每个 props.
。就像它没有看到类型的联合。还是我误会了什么?
基本上,如果道具有label
,或option
,我希望props
是LayersItemStatic & shared Types
类型,如果有currentLayer
在 props
中,我希望它们是 LayersItemDynamic & sharedTypes
.
那么我在这里错过了什么?
我正在努力实现这样的目标:
type SharedType = SharedDisplayAndEditTypes & {
required?: boolean;
validationMessage: string;
name: string;
};
type TextType = {
type: 'text';
children: string;
};
type NumberType = {
type: 'number';
children: number;
};
type InputType = TextType | NumberType;
type DropdownType = {
type: 'dropdown';
options: string[];
children: string;
};
type ColorType = {
type: 'color';
defaultValue: string;
};
export type DetailsItemEditProps = (DropdownType | InputType | ColorType) & SharedType;
考虑这个例子:
import { ReactElement } from 'react'
type LayersElement = {
tag: 'LayersElement'
}
export enum LayersItemOptionsEnum {
OPERATOR,
HEADER,
}
type sharedTypes = {
children: string | ReactElement;
};
type LayersItemStatic = sharedTypes & {
label: string;
option: LayersItemOptionsEnum;
};
type LayersItemDynamic = sharedTypes & {
currentLayer: LayersElement;
};
export type LayersItemProps = (LayersItemDynamic | LayersItemStatic) & sharedTypes;
declare var props: LayersItemProps;
props.children // ok
只允许使用 children
道具,因为它是联合的每个元素的公共道具。
由于没有人知道实际上允许联合的哪个元素,TS 决定只允许您使用对联合的每个元素都是安全的属性。
考虑这个较小的例子:
type LayersItemStatic = {
label: string;
option: string;
};
type LayersItemDynamic = {
currentLayer: string;
};
export type LayersItemProps = LayersItemDynamic | LayersItemStatic
declare var props: LayersItemProps;
因为没有常用道具,所以你不能使用任何道具。
我认为这种类型不正确:
export type LayersItemProps = (LayersItemDynamic | LayersItemStatic) & sharedTypes
由于LayersItemDynamic | LayersItemStatic
缩减为{}
而LayersItemProps
基本等于sharedTypes
.
因为您已经将 & sharedType
添加到两个 LayersItemDynamic | LayersItemStatic
中,您需要重写您的类型 LayersItemProps
如下:
import { ReactElement } from 'react'
type LayersElement = {
tag: 'LayersElement'
}
export enum LayersItemOptionsEnum {
OPERATOR,
HEADER,
}
type sharedTypes = {
children: string | ReactElement;
};
type LayersItemStatic = sharedTypes & {
label: string;
option: LayersItemOptionsEnum;
};
type LayersItemDynamic = sharedTypes & {
currentLayer: LayersElement;
};
const hasProperty = <Obj, Prop extends string>(obj: Obj, prop: Prop)
: obj is Obj & Record<Prop, unknown> =>
Object.prototype.hasOwnProperty.call(obj, prop);
export type LayersItemProps = LayersItemDynamic | LayersItemStatic
const isDynamic = (props: LayersItemProps): props is LayersItemDynamic => hasProperty(props, 'currentLayer')
const isStatic = (props: LayersItemProps): props is LayersItemStatic => hasProperty(props, 'label')
declare var props: LayersItemProps;
if (isDynamic(props)) {
props.currentLayer // ok
}
if (isStatic(props)) {
props.label // ok
props.option // ok
}