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
对象中才能执行此操作;您不能将它们复制到其他变量并保持 props
和 useStateProps
之间的相关性。所以 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;
}
};
可以看到编译成功了。好的,希望有所帮助;祝你好运!
我的代码中有两个接口,我想 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
对象中才能执行此操作;您不能将它们复制到其他变量并保持 props
和 useStateProps
之间的相关性。所以 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;
}
};
可以看到编译成功了。好的,希望有所帮助;祝你好运!