10

I'd like to create a common function which will take an object, then do some transformations and return new object with same keys and different values. I'm trying to make it "strongly-typed", so everyone who uses it will have benefits of TS and non-existing keys should throw an error.

What I have for now:

const hash = {
  "first": 1,
  "second": 2,
  "third": 3,
}

type Mapper<T> = {
  [key in keyof T]: number
}

type Result<T>= {
  [key in keyof T]: () => number
}

const transform = <T>(mapper: Mapper<T>) => {
  const result = {} as Result<T>

  (Object.keys(mapper) as (keyof T)[]).map(key => {
    result[key] = () => mapper[key]
  })

  return result
}

type Hash = typeof hash

const a = transform<Hash>(hash)

a.first()
// a.fifth() OK error

It works well, but I'm looking for solutions to solve this:

  1. Remove type assertion const result = {} as Result<T>

  2. Remove type assertion (Object.keys(mapper) as (keyof T)[]) (or use Object.entries, but seems it also requires type assertion in this case)

Could I implement the same, but in more "clean" way in Typescript?

1 Answer 1

12

Object.keys returns always string[] therefore you will need the casting.

A smaller & more robust version would use Object.fromEntries. Another small improvement would be to use the type of the original key, with T[Key].

const hash = {
  "first": "someString",
  "second": 2,
  "third": 3,
};

type Result<T>= {
  [Key in keyof T]: () => T[Key]
};

const transform = <T extends object>(obj: T): Result<T> => {
  return Object.fromEntries(
    Object.keys(obj).map(
        (key) => [key, () => obj[key as keyof T]]
    )
  ) as Result<T>;
}

const a = transform(hash);

const first = a.first(); // returns "string"
//    ^? const first: string
const second = a.second(); // return "number"
//    ^? const second: number

Playground link

Sign up to request clarification or add additional context in comments.

3 Comments

What the heck who could think changing : to in would fix that?Thanks!
@T.J.Crowder, Changed it to more elegant / modern solution, Object.fromEntries (which is much faster BTW)
@felixmosh - Nice! There was a typo in the code, so I went ahead and fixed it and formatted the code so it would cause horizontal scrolling, and added TypeScript playground link. Happy coding!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.