I want to make my End-to-End testing easier and typesafer, by collecting and transforming the data-attributes in a typed constant object. However, I cannot make it work.
How can I create an union type out of an attribute value of multiple objects within an array?
interface Itest {
name: string
values: readonly string[]
}
const testAttributes: readonly Itest[] = [
{
name: "testid",
values: [
"playbarQueueIcon",
"queueBar",
"playbarPlayButton",
"playbarPauseButton",
"playbarPreviousButton",
"playbarNextButton",
// ...
] as const,
} as const,
{
name: "testgroup",
values: ["queueNextTracks", "queuePreviousTracks"] as const,
} as const,
] as const
// ***********************
// Why does this not work?
// ***********************
type ITest = typeof testAttributes[number]["values"][number]
const attr = testAttributes.reduce((acc, {name, values}) => {
for (const value of values) {
acc[value] = `[data-${name}=${value}]`
}
return acc
}, {} as Record<ITest, string>
)
attr.queueBarXXXX // => Should not work
attr.queueBar // => Should work
CodePudding user response:
Manually setting a type via : readonly Itest[]
overrides what could be inferred. So values
is string[]
because that overrides the as const
assertion. Remove that and you get the union I think you expect.
If you want testAttributes
to satisfy the Itest[]
type but be inferred to something more specific you need to wait for the satisfies
operator to land in released typescript: https://github.com/microsoft/TypeScript/issues/47920
Or use a function:
function makeTestArray<T extends Itest[]>(arr: T): T { return arr }
const testAttributes = makeTestArray([...]) // data goes here.