TypeScript 中的条件泛型类型使用区分联合

Conditional Generic Types in TypeScript use Discriminated Union

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

接口代码如下:

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;
      }
    };

Property 'setCityId' does not exist on type 'createUserToSiteMutateUseStates | updateStoreSpatialCommitmentsVariablesUseState'.

Property 'setCityId' does not exist on type 'updateStoreSpatialCommitmentsVariablesUseState'.ts(2339)

我该如何解决这个错误? whichType 有问题吗?

你的条件类型是通用的并且需要一个类型参数,但你没有在你的 Props 接口中给它一个。 属性 useStateProps?: whichType<type> 无法编译,因为 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; const 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