Yanis
Yanis

Reputation: 5007

Trying to make autocomplete work in TypeScript for my library

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?

Upvotes: 1

Views: 932

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250396

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

Upvotes: 1

Related Questions