简体   繁体   English

TypeScript 中的条件泛型类型使用 Discriminated Union

[英]Conditional Generic Types in TypeScript use Discriminated Union

I have two interfaces in my code that I want to select one type between these two.我的代码中有两个接口,我想在这两个接口之间选择一种类型。

Here is the code for the interfaces:下面是接口的代码:

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

I created a type to recognition of true interface:我创建了一个类型来识别真正的界面:

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

And finally I used the whichType :最后我使用了whichType

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

But when I use Props , I get this error:但是当我使用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 |类型“createUserToSiteMutateUseStates”上不存在属性“setCityId” | updateStoreSpatialCommitmentsVariablesUseState'. updateStoreSpatialCommitmentsVariablesUseState'。

Property 'setCityId' does not exist on type 'updateStoreSpatialCommitmentsVariablesUseState'.ts(2339)类型“updateStoreSpatialCommitmentsVariablesUseState”.ts(2339) 上不存在属性“setCityId”

How can I fix this error?我该如何解决这个错误? Is a problem in whichType ? whichType有问题吗?

Your conditional type is generic and requires a type parameter, but you haven't given it one inside your Props interface.你的条件类型是泛型的,需要一个类型参数,但你没有在你的Props接口中给它一个。 The property useStateProps?: whichType<type> doesn't compile because type is not a type;属性useStateProps?: whichType<type>不能编译,因为type不是类型; it seems to be the key name of another property.它似乎是另一个属性的键名。 In order for that to work you need Props to itself be generic.为了Props起作用,你需要Props本身是通用的。

Instead of using generics or conditional types I'd suggest that you make Props a discriminated union to get the desired behavior.我建议您不要使用泛型或条件类型,而是让Props成为可区分的联合以获得所需的行为。 Here's one way to do it that seems similar to your current setup:这是一种与您当前设置类似的方法:

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

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

If you inspect that, Props is equivalent to:如果你检查一下, Props相当于:

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

So now the Props type has a type discriminant property which can be used to narrow the type to one of the three union members if you switch on it.所以现在Props类型有一个type判别属性,如果你打开它,它可以用来将类型缩小到三个联合成员之一。 Note that you have to keep the properties in a single Props object to do this;请注意,您必须将属性保存在单个Props对象中才能执行此操作; you can't copy them to other variables and maintain the correlation between props and useStateProps .您不能将它们复制到其他变量并保持propsuseStateProps之间的相关性。 So if (props.type === "...") { props.useStateProps... } else ... will work, but `const type = props.type;所以if (props.type === "...") { props.useStateProps... } else ...会起作用,但是 `const type = props.type; const useStateProps = props.useStateProps; const useStateProps = props.useStateProps; if (type == "...") { useStateProps... } else ..." will not. if (type == "...") { useStateProps... } else ..." 不会。

So this would be how you'd write it:所以这将是你编写它的方式:

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

You can see that it compiles without error now.你可以看到它现在编译没有错误。 Okay, hope that helps;好的,希望有帮助; good luck!祝你好运!

Link to code 代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM