У меня есть код TypeScript, который аккуратно сопоставляет типы с их возможными значениями:
export const randomMappings = {
coin: ['heads', 'tails'],
d4: [1, 2, 3, 4],
d6: [1, 2, 3, 4, 5, 6],
d10: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
} as const;
export type RandomType = keyof typeof randomMappings;
export type RandomValue<T extends RandomType> = typeof randomMappings[T][number];
// RandomValue<'coin'> is 'heads'|'tails'; RandomValue<'d4'> is 1|2|3|4 and so on.
export type RandomResults = {
[T in RandomType]?: RandomValue<T>;
};
export function pickRandomValues(types: RandomType[]): RandomResults {
return Object.fromEntries(
types.map((type) => [
type,
randomMappings[type][Math.floor(Math.random() * randomMappings[type].length)],
]),
);
}
Я хотел бы обеспечить, чтобы тип, возвращаемый pickRandomValues
, был картой, которая содержала только ключи, представленные в аргументе types
, вместо того, чтобы иметь все возможные ключи как необязательные.
Например:
const x = pickRandomValues(['coin', 'd6']);
console.log(x.coin, x.d6); //works
console.log(x.d10); //should fail because d10 is not present in x
Я думаю, что способ определения RandomValue<T>
довольно элегантен, поэтому я не хотел бы его менять, если это возможно.
Есть ли способ сделать это? Я был бы не против изменить аргумент types
на карту вместо массива, чтобы я мог сделать что-то вроде {[T in keyof typeof types]: RandomValue<T>}
, но то, что я пробовал, не работает, потому что, если я хочу, чтобы он позволял передавать объект только с интересующими меня ключами тип будет таким же, как сейчас RandomResults
(все ключи необязательны).