0

I want to type a JavaScript Proxy that allows access to arbitrary properties. A contrived example, an object that maps every property to it's own property name:

const proxy = new Proxy({}, {
  get(target, property) {
    return prop;
  }
});
proxy.foo // evaluates to "foo"
// Property 'foo' does not exist on type '{}'.ts(2339)

I don't expect TypeScript to automatically infer proxy.foo exists, but I would like to provide a type such that it knows it exists and the property's value type depends on the property name.

The following mapped type at least prevents TypeScript from complaining about the property not existing, however it infers the type as string rather than the more specific "foo" property name:

const proxy = new Proxy<{ [T in string]: T }>({}, {
  get(target, prop) {
    return prop;
  }
});
proxy.foo // inferred as `string` instead of `"foo"`

I have also tried { readonly [T in string]: T }.

Interestingly ({} as { [T in "foo" | "bar"]: T }).foo will be inferred as `"foo", but I can't enumerate all possible keys.

Is there some way to get TypeScript to use the exact key in the value's type in a mapped type, or some other way of precisely typing a Proxy with dynamic properties?

tlrobinson
  • 2,812
  • 1
  • 33
  • 35
  • Would `keyof` be of help? – Anatoly Jan 28 '23 at 08:53
  • 1
    This is not possible, as described in the declined suggestion [microsoft/TypeScript#22509](https://github.com/microsoft/TypeScript/issues/22509). Does that fully address your question? If so I will write up an answer; if not, what am I missing? – jcalz Jan 28 '23 at 17:32

1 Answers1

0

Maybe you could create a helper type to create such object with same key and value first

// make an object with same key and value
type Fallback<Keys extends string> = { [K in Keys]: K };

type FooBar = Fallback<'foo' | 'bar'>

const foobar = new Proxy<FooBar>({} as FooBar, {...})
foobar.bar // inferred as 'bar'