Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: Create object with same keys but different values

Tags:

I have the following initial object

const initialValues = { name: 'Jon', email: '[email protected]' }

I would like to create an identical object except where all the values are boolean and default to false. Like so

const expected = { name: false, email: false }

I created the following function which does what I want

const expected = cloneWithDefaults<typeof initialValues>(initialValues)

function cloneWithDefaults<T>(values: T) {
  type U = { [K in keyof T]: boolean }
  const keys = Object.keys(values) as Array<keyof T>
  const partial: Partial<U> = keys.reduce<Partial<U>>((acc, cur) => {
    acc[cur] = false
    return acc
  }, {})
  const final = partial as U
  return final
}

I also created a second version which does not use reduce

function createCloneWithDefaultsV2<T extends { [key: string]: unknown }>(values: T) {
  type U = { [K in keyof T]: boolean }
  const keys = Object.keys(values) as Array<keyof U>
  const partial: Partial<U> = {}
  for (let k in keys) {
    partial[k] = false
  }
  const final = partial as U
  return final
}

I wonder if there is a better / more succinct way of doing this. In particular I would like to get rid of the two uses of as if possible.

In the v2 I wonder if there is any preference for unknown as opposed to any.

like image 266
david_adler Avatar asked May 11 '19 13:05

david_adler


People also ask

Can an object key have more than one value?

Each key can only have one value. But the same value can occur more than once inside a Hash, while each key can occur only once.

Can JavaScript object have same keys?

No, JavaScript objects cannot have duplicate keys. The keys must all be unique.

What is Keyof in TypeScript?

keyof is a keyword in TypeScript which is used to extract the key type from an object type.


1 Answers

Here's how I would write it:

    function cloneWithDefaults<T>(values: T) {
        return <{[key in keyof T]: boolean}> Object.entries(values).reduce((p, [k, v]) => Object.assign(p, { [k]: false }), {});
    }
    const initialValues = { name: 'Jon', email: '[email protected]' };
    const expected = cloneWithDefaults(initialValues);

Due to the reduce() call, I don't see an option without a cast. (Either from partial or from any.) Note that Object.entries() requires downlevelIteration ts compiler option to be true (https://www.typescriptlang.org/docs/handbook/compiler-options.html).

like image 151
Christoph Lütjen Avatar answered Nov 11 '22 04:11

Christoph Lütjen