1

SO, I have a function, that takes values of object and return another object that use those values as keys. It looks something like this:

function fn(actions) {
  return keys.reduce((acc, m) => {
    const name = actions[m]
    acc[name] = () => { /* some function */}
    return acc
  }, {})
}

Now, somehow I want to type it so that when I call it

res = fn({"something": "go", "something else": "run"})
res. // ...

autocomplete would work to suggest that there are indeed 2 methods can be invoked "go" and "run".

So basically I expect res to have type of { [key in 'go' | 'run']: Function }.

Is that possible to achieve with TS?

1 Answer 1

1

You need to capture the string literal types in the object. You could use as const on the object itself, or you can use the trick that TS will preserve the string literal types if the string literal is assigned to a generic type parameter.

With the string literal types you can then create the mapped type you need:

function fn<V extends string, T extends Record<keyof T, V>>(actions: T) {
  var keys = Object.keys(actions) as Array<keyof T>
  return keys.reduce((acc, m) => {
    const name = actions[m]
    acc[name] = () => { /* some function */}
    return acc
  }, {} as { [P in T[keyof T]]: () => void })
}

let res = fn({"something": "go", "something else": "run"})
res.go()
res.run();
res.Run()  // err

Play

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

Comments

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.