我有一个配置对象的键枚举,它呈现一个Material-UI Drawer Component,其中抽屉中的组件要么匹配一个单个组件,要么匹配每个子主题节中的一组组件:
export enum InsuranceTopicPrimaryKeys {
POLICY_HOLDERS = "policyHolders",
INSURANCE_PROVIDERS = "providers",
INSURANCE_TYPE = "type",
CLAIMS = "claims",
}
export enum InsuranceTopicSecondaryKeys {
POLICY_MEMBERS = "policyMembers",
}
export type InsuranceTopicKeys =
| InsuranceTopicPrimaryKeys
| InsuranceTopicSecondaryKeys;
export enum SectionKeys {
CLAIMANTS = "claimants",
FULFILLED_CLAIMS = "fullfilledClaims",
UNFULFILLED_CLAIMS = "unfullfilledClaims",
}
配置对象如下所示:
export const TOPICS: Record<
InsuranceTopicPrimaryKeys,
TopicConfiguration | TopicConfigurationGrouped
> = {
[InsuranceTopicPrimaryKeys.POLICY_HOLDERS]: {
key: InsuranceTopicPrimaryKeys.POLICY_HOLDERS,
secondaryKey: InsuranceTopicSecondaryKeys.POLICY_MEMBERS,
title: "Policy Holders",
component: (props: TopicDrawerProps) => (
<TopicDrawer hasSecondary={true} {...props} />
),
topicSelector: keyedTopicSelector.showAll,
secondaryTopic: {
key: InsuranceTopicSecondaryKeys.POLICY_MEMBERS,
primaryKey: InsuranceTopicPrimaryKeys.POLICY_HOLDERS,
title: "Policy Members",
component: (props: TopicDrawerProps) => (
<TopicDrawer isSecondary={true} {...props} />
),
topicSelector: keyedTopicSelector.showRelated,
},
},
[InsuranceTopicPrimaryKeys.INSURANCE_PROVIDERS]: {
key: InsuranceTopicPrimaryKeys.INSURANCE_PROVIDERS,
title: "Policy Holders",
component: TopicDrawerSimple,
topicSelector: keyedTopicSelector.showAll,
},
[InsuranceTopicPrimaryKeys.INSURANCE_TYPE]: {
key: InsuranceTopicPrimaryKeys.INSURANCE_PROVIDERS,
title: "Policy Holders",
component: TopicDrawerSimple,
topicSelector: keyedTopicSelector.showAll,
},
[InsuranceTopicPrimaryKeys.CLAIMS]: {
key: InsuranceTopicPrimaryKeys.CLAIMS,
title: "Claims",
component: TopicDrawerGroup,
topicSelectorCreator: createMultiKeyedTopicSelector,
sections: [
SectionKeys.CLAIMANTS,
SectionKeys.FULFILLED_CLAIMS,
SectionKeys.UNFULFILLED_CLAIMS,
],
},
};
export type SectionConfig = {
key: SectionKeys;
title: string;
};
export const SECTIONS: Record<SectionKeys, SectionConfig> = {
[SectionKeys.CLAIMANTS]: {
key: SectionKeys.CLAIMANTS,
title: "Claimants",
},
[SectionKeys.FULFILLED_CLAIMS]: {
key: SectionKeys.FULFILLED_CLAIMS,
title: "Fulfilled Claims",
},
[SectionKeys.UNFULFILLED_CLAIMS]: {
key: SectionKeys.UNFULFILLED_CLAIMS,
title: "Unfulfilled Claims",
},
};
配置(TopicConfiguration
、SecondaryTopicConfiguration
和TopicConfigurationGrouped
)共享一个基本类型,它们扩展该基本类型:
export interface BaseTopicConfig {
key: InsuranceTopicKeys;
title: string;
secondaryKey?: InsuranceTopicSecondaryKeys;
secondaryTopic?: SecondaryTopicConfiguration;
}
export interface TopicConfiguration extends BaseTopicConfig {
topicSelector: TopicSelector;
component: TopicComponent;
}
export interface SecondaryTopicConfiguration extends TopicConfiguration {
primaryKey: InsuranceTopicPrimaryKeys;
}
export interface TopicConfigurationGrouped extends BaseTopicConfig {
topicSelectorCreator: TopicSelectorCreator;
component: TopicComponentGroup;
sections: SectionKeys[];
}
然而,有时候我想查找InsuranceTopicPrimaryKeys.CLAIMS
的配置,并且快捷方式必须向TS“证明”它的配置只会是TopicConfigurationGrouped
类型。由于传统原因,我不能拆分配置,以及我想访问共享密钥的情况。
所以我希望我可以创建一个'keys'的子集,并拥有两个记录的并集(见下文),而不是一个值是类型并集的记录(Record<InsuranceTopicPrimaryKeys, TopicConfiguration | TopicConfigurationGrouped>
)。
// subset that match config of type TopicConfigurationGrouped
export type TopicGroups = InsuranceTopicPrimaryKeys.CLAIMS
然后将TOPICS
的类型设置为:
const TOPICS: Record<InsuranceTopicPrimaryKeys, TopicConfiguration> | Record<TopicGroups, TopicConfigurationGrouped>
但是现在当我用这个helper函数来获取配置时:
const isPrimaryTopic = (
topicType: string
): topicType is InsuranceTopicPrimaryKeys =>
Object.values(InsuranceTopicPrimaryKeys).includes(
topicType as InsuranceTopicPrimaryKeys
);
const getConfig = (
configKey: string
):
| SecondaryTopicConfiguration
| TopicConfiguration
| TopicConfigurationGrouped
| undefined =>
isPrimaryTopic(configKey)
? TOPICS[configKey as InsuranceTopicPrimaryKeys]
: Object.values(TOPICS).find(
(topicConfig) => topicConfig?.secondaryKey === configKey
)?.secondaryTopic;
我得到这个错误:
元素隐式具有“any”类型,因为类型“InsuranceTopicPrimaryKeys”的表达式不能用于索引类型“Record〈InsuranceTopicPrimaryKeys,TopicConfiguration〉”|Record〈InsuranceTopicPrimaryKeys.CLAIMS,TopicConfigurationGrouped〉'。属性“[InsuranceTopicPrimaryKeys.POLICY_HOLDERS]”在类型“Record〈InsuranceTopicPrimaryKeys,TopicConfiguration〉”上不存在|记录〈InsuranceTopicPrimaryKeys.CLAIMS,TopicConfigurationGrouped〉’。(7053)
如何在配置Map对象(TOPICS和/或链接的playground TOPICS_TWO)中配置类型,以便此助手函数(和其他函数)可以推断InsuranceTopicPrimaryKeys
类型可以索引不同记录的并集?
附加类型,使这一个工作的例子是在这个typescript操场
2条答案
按热度按时间xe55xuns1#
TOPICS_TWO
的类型不应该是并集。由于InsuranceTopicPrimaryKeys
包含TopicGroups
,因此应首先排除TopicGroups
。然后可以将该记录与新记录TopicGroups
相交。Playground
wydwbb8l2#
您收到的错误消息是因为
TOPICS
的类型与您定义为getConfig
的返回类型的联合类型不兼容。类型TOPICS
是具有属于InsuranceTopicPrimaryKeys
枚举的键的记录,其值可以是TopicConfiguration
或TopicConfigurationGrouped
。因此,当您尝试使用string
类型的索引访问TOPICS
的值时(由getConfig
的configKey参数返回),TypeScript推断索引的类型为InsuranceTopicPrimaryKeys
,这与string
不兼容。这是因为TypeScript无法确定字符串是否实际上是枚举值之一。修复此错误的一种方法是将
getConfig
的返回类型更改为仅TopicConfiguration
和TopicConfigurationGrouped
的并集,因为SecondaryTopicConfiguration
扩展了TopicConfiguration
。当使用InsuranceTopicPrimaryKeys
类型的索引访问时,TypeScript将能够推断TOPICS
返回的值的正确类型。这是getConfig
的更新版本:在这个版本中,
configKey
的类型为InsuranceTopicKeys
,它是InsuranceTopicPrimaryKeys
和InsuranceTopicSecondaryKeys
的并集。这确保了用于访问TOPICS
的索引是正确的类型。请注意,您不需要定义单独的类型
TopicGroups
来表示属于TopicConfigurationGrouped
的键。相反,您可以使用Record
实用程序类型创建一个类型,将TOPICS
的键Map到它们各自的值类型,然后使用条件类型过滤掉不属于TopicConfigurationGrouped
的键。下面是一个示例:在本例中,
GroupedTopicKeys
类型使用Map类型定义,该Map类型过滤掉TOPICS
中不属于TopicConfigurationGrouped
的键。结果类型是剩余键的并集。然后,groupedKeys
变量被定义为属于TopicConfigurationGrouped
的键的数组。最后,groupedTopics
变量被定义为具有GroupedTopicKeys
类型的键和TopicConfigurationGrouped
类型的值的记录。