【问题标题】:Conditional Generic Types in TypeScript use Discriminated UnionTypeScript 中的条件泛型类型使用有区别的联合
【发布时间】:2020-04-14 13:51:36
【问题描述】:

我的代码中有两个接口,我想在这两者之间选择一种类型。

接口代码如下:

interface createUserToSiteMutateUseStates {
  setStateId: (value: React.SetStateAction<string | null | undefined>) => void;
  StateId: string | null | undefined;
  setCityId: (value: React.SetStateAction<string | null | undefined>) => void;
}

interface updateStoreSpatialCommitmentsVariablesUseState {
  setStateSelected: (
    value: React.SetStateAction<SelectorOptions[] | undefined | null>
  ) => void;
}

我创建了一个类型来识别真正的接口:

type whichType<T> = T extends "createUserToSiteMutate"
  ? createUserToSiteMutateUseStates
  : T extends "updateStoreSpatialCommitmentsVariables"
  ? updateStoreSpatialCommitmentsVariablesUseState
  : null;

最后我使用了whichType

export interface Props {
  type:
    | "createUserToSiteMutate"
    | "createUnitVariables"
    | "updateStoreSpatialCommitmentsVariables";
  useStateProps?: whichType<type>;
}

但是当我使用Props 时,我得到了这个错误:

const handleChange = (option: SelectorOptions) => {
      switch (type) {
        case "createUserToSiteMutate":
          useStateProps!.setCityId && useStateProps!.setCityId(null);
          useStateProps!.setUniversityId &&
            useStateProps!.setUniversityId(null);
          useStateProps!.setOrganizationId &&
            useStateProps!.setOrganizationId(null);
          useStateProps!.setUnitId && useStateProps!.setUnitId(null);
          useStateProps!.setStateId && useStateProps!.setStateId(option.value);
        default:
          break;
      }
    };

“createUserToSiteMutateUseStates”类型上不存在属性“setCityId”| updateStoreSpatialCommitmentsVariablesUseState'。

“updateStoreSpatialCommitmentsVariablesUseState”类型上不存在属性“setCityId”。ts(2339)

如何解决此错误? whichType有问题吗?

【问题讨论】:

  • updateStoreSpatialCommitmentsVariablesUseState 中没有 setCityId 但我收到此错误。
  • 请考虑将此处的代码编辑为真正的minimal reproducible example,如How to Ask 中所述。现在有很多错误似乎与您的问题无关。如果有人将代码放入独立的 IDE 中,他们应该能够重现您的特定问题,而无需花时间尝试修复或选择性地忽略其他问题。

标签: javascript reactjs typescript typechecking


【解决方案1】:

您的条件类型是通用的并且需要一个类型参数,但是您还没有在Props 接口中给它一个。属性useStateProps?: whichType&lt;type&gt; 无法编译,因为type 不是类型;它似乎是另一个属性的键名。为了使它起作用,您需要 Props 本身是通用的。

我建议您不要使用泛型或条件类型,而是将Props 设为discriminated union 以获得所需的行为。这是一种与您当前的设置类似的方法:

interface TypeMap {
    createUserToSiteMutate: CreateUserToSiteMutateUseStates,
    updateStoreSpatialCommitmentsVariables: UpdateStoreSpatialCommitmentsVariablesUseState,
    createUnitVariables: null
}

type Props = { [K in keyof TypeMap]: {
    type: K,
    useStateProps?: TypeMap[K];
} }[keyof TypeMap];

如果您检查,Props 相当于:

type Props = {
    type: "createUserToSiteMutate";
    useStateProps?: CreateUserToSiteMutateUseStates | undefined;
} | {
    type: "updateStoreSpatialCommitmentsVariables";
    useStateProps?: UpdateStoreSpatialCommitmentsVariablesUseState | undefined;
} | {
    type: "createUnitVariables";
    useStateProps?: null | undefined;
}

所以现在Props 类型有一个type discriminant 属性,如果您打开它,可以使用该属性将类型缩小到三个联合成员之一。请注意,您必须将属性保存在单个 Props 对象中才能执行此操作;您不能将它们复制到其他变量并保持propsuseStateProps 之间的相关性。所以if (props.type === "...") { props.useStateProps... } else ... 会起作用,但是 `const type = props.type;常量 useStateProps = props.useStateProps; if (type == "...") { useStateProps... } else ..." 不会。

所以你会这样写:

declare const props: Props;

const handleChange = (option: SelectorOptions) => {
    switch (props.type) {
        case "createUserToSiteMutate":
            props.useStateProps!.setCityId && props.useStateProps!.setCityId(null);
            props.useStateProps!.setStateId && props.useStateProps!.setStateId(option.value);
        default:
            break;
    }
};

您现在可以看到它编译没有错误。好的,希望有帮助;祝你好运!

Link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-03
    • 2020-04-12
    • 2021-02-14
    • 2021-06-09
    • 2021-02-26
    • 2020-12-24
    • 2019-07-14
    • 2020-07-31
    相关资源
    最近更新 更多