ARTICLE AD BOX
This is a known deficiency in TypeScript, see microsoft/TypeScript#13948. When you use a computed property whose key is not of a single string literal type in an object literal, the compiler widens the type of the key all the way to string, resulting in a type with a string index signature. This is usually not what people want to see, but it happens. Now that pattern template literal index signatures are supported, this widening is even more noticeable (as I noted in this comment on the referenced GitHub issue), as you've just experienced. I don't know when or if this will be addressed.
In the meantime, the workaround I usually employ is to make a kv() function that takes a key and a value and produces a computed-key object with a more appropriate type:
const kv = <K extends PropertyKey, V>(k: K, v: V) => ({ [k]: v }) as { [P in K]: { [Q in P]: V } }[K]That return type is a "distributive Record<K, V> type" where any unions in the K type are distributed out to the final type, so that if the key is of type A | B | C and the value is of type V then the output is of type Record<A, V> | Record<B, V> | Record<C, V> (so it has some key) instead of the incorrect Record<A | B | C, V> (which has all keys).
You can test it here for template literals:
const obj3 = kv(b, 1); /* const obj3: { [x: `b/${string}`]: number; } */And for unions as well:
const obj4 = kv(Math.random() < 0.5 ? a : b, 3); /* const obj4: { [x: `b/${string}`]: number; } | { a: number; } */