通常,当我在TypeScript中具有字符串文字的并集时,我想创建一个从字符串到其他值的映射。这涉及创建一个不允许值推断的类型,这在我也要访问值类型时可能会很烦人。例如,这是一个基本的挂断:
type UserPersona =
| "entrepreneur"
| "programmer"
| "designer"
| "product_manager"
| "marketing_sales"
| "customer_support"
| "operations_hr"
const userPersonaDisplayNames: { [key in UserPersona]: string } = {
entrepreneur: "Entrepreneur",
programmer: "Programmer",
designer: "Designer",
product_manager: "Product Manager",
marketing_sales: "Marketing & Sales",
customer_support: "Customer Support",
operations_hr: "Operations & HR",
}
这里的问题是userPersonaDisplayNames
的值是string
类型,而不是其文字值。
当我离开类型时,键和和值是文字类型,这很不错,但是键不再受联合类型的约束。
const userPersonaDisplayNames = {
entrepreneur: "Entrepreneur",
programmer: "Programmer",
designer: "Designer",
product_manager: "Product Manager",
marketing_sales: "Marketing & Sales",
customer_support: "Customer Support",
operations_hr: "Operations & HR",
}
我发现的一种破解方法是使用扩展来断言。
type Assert<A,B> = A extends B
type assertPersonaKeys = Assert<keyof userPersonaDisplayNames, UserPersona>
这行得通,但是有点毛病。我周围有TSLint抱怨的未使用类型。
似乎infer
关键字正是我在寻找的关键字,但是我不确定它如何工作,在我的情况下它不起作用。理想情况下,我可以做这样的事情:
const userPersonaDisplayNames: { [key in UserPersona]: infer } = {
entrepreneur: "Entrepreneur",
programmer: "Programmer",
designer: "Designer",
product_manager: "Product Manager",
marketing_sales: "Marketing & Sales",
customer_support: "Customer Support",
operations_hr: "Operations & HR",
}
有什么想法可以彻底解决这个问题吗?
答案 0 :(得分:2)
使用辅助函数来表示要查看的约束,然后调用它吗?因为它调用(t => t)(obj)
而不是仅使用obj
,所以运行时开销非常小。
const asUserPersonaDisplayNames = <
S extends string, // allow S to be inferred as a string literal
T extends Record<UserPersona, S> & // require keys from UserPersona
Record<Exclude<keyof T, UserPersona>, never> // disallow keys not from UserPersona
>(t: T) => t
const userPersonaDisplayNames = asUserPersonaDisplayNames({
entrepreneur: "Entrepreneur",
programmer: "Programmer",
designer: "Designer",
product_manager: "Product Manager",
marketing_sales: "Marketing & Sales",
customer_support: "Customer Support",
operations_hr: "Operations & HR",
}); // type has fully string-literal values
const missing = asUserPersonaDisplayNames({
entrepreneur: "Entrepreneur",
programmer: "Programmer",
product_manager: "Product Manager",
marketing_sales: "Marketing & Sales",
customer_support: "Customer Support",
operations_hr: "Operations & HR",
}) // error, property "designer" is missing
const extra = asUserPersonaDisplayNames({
candlestick_maker: "Rub a Dub Dub",
entrepreneur: "Entrepreneur",
programmer: "Programmer",
designer: "Designer",
product_manager: "Product Manager",
marketing_sales: "Marketing & Sales",
customer_support: "Customer Support",
operations_hr: "Operations & HR",
}); // error, property "candlestick_maker" is extra
const notString = asUserPersonaDisplayNames({
entrepreneur: 25,
programmer: "Programmer",
designer: "Designer",
product_manager: "Product Manager",
marketing_sales: "Marketing & Sales",
customer_support: "Customer Support",
operations_hr: "Operations & HR",
}); // error, number is not expected
希望有所帮助;祝你好运!