apple: { color: "red", mass: 100 }, grape: { color: "red", mass: 5 }, banana: { color: "yellow", mass: 183 }, lemon: { color: "yellow", mass: 80 }, pear: { color: "green", mass: 178 }, orange: { color: "orange", mass: 262 }, raspberry: { color: "red", mass: 4 }, cherry: { color: "red", mass: 5 }, interface Dict { [k: string]: T // Array.prototype.map, but for Dict function mapDict(input: Dict, transform: (item: T, key: string) => S): Dict { const obj: Dict = {}; for (let x in input) { obj[x] = transform(input[x], x); return obj; // Array.prototype.filter, but for Dict function filterDict(input: Dict, predict: (item: T) => boolean): Dict { const obj: Dict = {}; for (let x in input) { if (predict(input[x])) { obj[x] = input[x]; return obj; // Array.prototype.reduce, but for Dict function reduceDict(input: Dict, reducer: (acc: V, curr: T) => V, initialValue: V): V { return Object.keys(input) .reduce((acc, curr) => { return reducer(acc, input[curr]); }, initialValue)

Test:

// MAP
const fruitsWithKgMass = mapDict(fruits, (fruit, name) => ({
  ...fruit,
  kg: 0.001 * fruit.mass,
  name,
const lemonName: string = fruitsWithKgMass.lemon.name
// @ts-ignore-error
const failLemonName: number = fruitsWithKgMass.lemon.name
assertOk(
  fruitsWithKgMass,
  "[MAP] mapDict returns something truthy"
assertEquals(
  fruitsWithKgMass.cherry.name,
  "cherry",
  '[MAP] .cherry has a "name" property with value "cherry"'
assertEquals(
  fruitsWithKgMass.cherry.kg,
  0.005,
  '[MAP] .cherry has a "kg" property with value 0.005'
assertEquals(
  fruitsWithKgMass.cherry.mass,
  '[MAP] .cherry has a "mass" property with value 5'
assertEquals(
  Object.keys(fruitsWithKgMass).length,
  "[MAP] fruitsWithKgMass should have 8 keys"
// FILTER
// only red fruits
const redFruits = filterDict(
  fruits,
  (fruit) => fruit.color === "red"
assertOk(
  redFruits,
  "[FILTER] filterDict returns something truthy"
assertEquals(
  Object.keys(redFruits).length,
  "[FILTER] 4 fruits that satisfy the filter"
assertEquals(
  Object.keys(redFruits).sort().join(", "),
  "apple, cherry, grape, raspberry",
  '[FILTER] Keys are "apple, cherry, grape, raspberry"'
// REDUCE
// If we had one of each fruit, how much would the total mass be?
const oneOfEachFruitMass = reduceDict(
  fruits,
  (currentMass, fruit) => currentMass + fruit.mass,
assertOk(
  redFruits,
  "[REDUCE] reduceDict returns something truthy"
assertEquals(
  typeof oneOfEachFruitMass,
  "number",
  "[REDUCE] reduceDict returns a number"
assertEquals(
  oneOfEachFruitMass,
  "[REDUCE] 817g mass if we had one of each fruit"