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,我希望propsLayersItemStatic & shared Types类型,如果有currentLayerprops 中,我希望它们是 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 道具,因为它是联合的每个元素的公共道具。

Best common type

由于没有人知道实际上允许联合的哪个元素,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

}

Playground