通过关键对象获取动态类型
Get Dynamic Type by key object
我需要将枚举值传递给模板键,上下文键只显示在 TemplatesMail 键中引用的属性
但 TS 显示所有属性,如 CancellationPolicyContext 和 AnotherMailContext
enum TemplateEnum {
CANCELLATION_POLICY = 'cancellation-policy',
ANOTHER_MAIL = 'another-mail'
}
type CancellationPolicyContext = {
name: string
cancellationDate: Date
}
type AnotherMailContext = {
value: number
}
type TemplatesMail = {
[TemplateEnum.CANCELLATION_POLICY]: CancellationPolicyContext
[TemplateEnum.ANOTHER_MAIL]: AnotherMailContext
}
type SendMailParams = {
template: TemplateEnum
context: TemplatesMail[TemplateEnum]
}
const params: SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY,
context: {
// need show only properties from CancellationPolicyContext
}
}
类型问题
type SendMailParams = {
template: TemplateEnum
context: TemplatesMail[TemplateEnum]
}
是它允许每个 属性 对应于 TemplateEnum
枚举 union 中的任何值。没有约束强制 template
和 context
属性分别对应于相同的枚举值。所以 {template: TemplateEnum.CANCELLATION_POLICY, context: AnotherMailContext}
类型的值是允许的。
你真正想要做的是说 对于 TemplateEnum
联盟中的每个 成员,你想要一个对应的 SendMailParams
类型.所以你想 分配 TemplateEnum
中的联合到原始 SendMailParams
类型。
为此,我们可以使用 分布式对象 类型(在 ms/TS#47109). It's a mapped type into which you immediately index 中创造,形式为 {[P in K]: F<P>}[K]
。如果 K
是K1 | K2 | K3 | ...
形式的类键类型(例如 TemplateEnum
)的并集,然后上面的分布式对象类型计算为 F<K1> | F<K2> | F<K3> | ...
.
这里是 SendMailParams
:
type SendMailParams = { [K in TemplateEnum]: {
template: K,
context: TemplatesMail[K]
} }[TemplateEnum];
IntelliSense 告诉你这个类型是
/* type SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY;
context: CancellationPolicyContext;
} | {
template: TemplateEnum.ANOTHER_MAIL;
context: AnotherMailContext;
} */
这是你想要的联盟。事实上它是一个 discriminated union 所以编译器将强制 template
属性 决定对象其余部分的形状。现在,如果您编写 template: TemplateEnum.CANCELLATION_POLICY
,类型检查器会立即将 context
属性 视为类型 CancellationPolicyContext
,并且您的 IntelliSense 只会向您显示适当的属性:
const params: SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY,
context: {
cancellationDate: new Date(),
name: "abc"
}
} // okay
const badParams: SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY,
context: {
value: 1 // error!
}
}
我需要将枚举值传递给模板键,上下文键只显示在 TemplatesMail 键中引用的属性 但 TS 显示所有属性,如 CancellationPolicyContext 和 AnotherMailContext
enum TemplateEnum {
CANCELLATION_POLICY = 'cancellation-policy',
ANOTHER_MAIL = 'another-mail'
}
type CancellationPolicyContext = {
name: string
cancellationDate: Date
}
type AnotherMailContext = {
value: number
}
type TemplatesMail = {
[TemplateEnum.CANCELLATION_POLICY]: CancellationPolicyContext
[TemplateEnum.ANOTHER_MAIL]: AnotherMailContext
}
type SendMailParams = {
template: TemplateEnum
context: TemplatesMail[TemplateEnum]
}
const params: SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY,
context: {
// need show only properties from CancellationPolicyContext
}
}
类型问题
type SendMailParams = {
template: TemplateEnum
context: TemplatesMail[TemplateEnum]
}
是它允许每个 属性 对应于 TemplateEnum
枚举 union 中的任何值。没有约束强制 template
和 context
属性分别对应于相同的枚举值。所以 {template: TemplateEnum.CANCELLATION_POLICY, context: AnotherMailContext}
类型的值是允许的。
你真正想要做的是说 对于 TemplateEnum
联盟中的每个 成员,你想要一个对应的 SendMailParams
类型.所以你想 分配 TemplateEnum
中的联合到原始 SendMailParams
类型。
为此,我们可以使用 分布式对象 类型(在 ms/TS#47109). It's a mapped type into which you immediately index 中创造,形式为 {[P in K]: F<P>}[K]
。如果 K
是K1 | K2 | K3 | ...
形式的类键类型(例如 TemplateEnum
)的并集,然后上面的分布式对象类型计算为 F<K1> | F<K2> | F<K3> | ...
.
这里是 SendMailParams
:
type SendMailParams = { [K in TemplateEnum]: {
template: K,
context: TemplatesMail[K]
} }[TemplateEnum];
IntelliSense 告诉你这个类型是
/* type SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY;
context: CancellationPolicyContext;
} | {
template: TemplateEnum.ANOTHER_MAIL;
context: AnotherMailContext;
} */
这是你想要的联盟。事实上它是一个 discriminated union 所以编译器将强制 template
属性 决定对象其余部分的形状。现在,如果您编写 template: TemplateEnum.CANCELLATION_POLICY
,类型检查器会立即将 context
属性 视为类型 CancellationPolicyContext
,并且您的 IntelliSense 只会向您显示适当的属性:
const params: SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY,
context: {
cancellationDate: new Date(),
name: "abc"
}
} // okay
const badParams: SendMailParams = {
template: TemplateEnum.CANCELLATION_POLICY,
context: {
value: 1 // error!
}
}