1

Is it possible to define a TypeScript type for an object where the key values are the literal key names themselves? For example:

declare const $: SpecialGenericType

$.prop // typed as the literal value "prop"

const values = [
  $.a,
  $.b,
  $.c
] as const

// values has the type (and value) ["a", "b", "c"]

The $ object could be implemented using a Proxy, but I'm not sure how to implement the SpecialGenericType. The type would need to allow any string as a key, but the values would need to be typed as the string literal of its key name (so Record<string, string> does not work in this case). For example, values above would have the tuple type ["a", "b", "c"].

2 Answers 2

2

What you're looking for is not currently possible in TypeScript. It works if you have some finite union of string literal keys, but not for all of string. There is an open suggestion at microsoft/TypeScript#22509 asking for this exact thing (called Thing instead of SpecialGenericType in the description), but there hasn't been any movement. The chief language architect said

This really is a request to add compiler support for ECMAScript proxy objects, i.e. compiler knowledge of the relationship between property access operations and the get and set proxy methods. It is simply not possible to model that with our current type system features (because nothing allows you to capture the literal type corresponding to the property name in a property access).

You might want to go to that issue and give it a 👍 or describe why you think your use case is compelling, but I doubt that it will be implemented anytime soon. Oh well, at least there's something like a definitive answer to this question, even if it is "no". Good luck!

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

1 Comment

This issue was closed in June 2021: github.com/microsoft/TypeScript/issues/22509
0

If I understand correctly, this is what you'd like:

type SpecialGenericType<T extends object> = {
  [K in keyof T]: K
};

function proxify<T extends object>(source: T) {
  const proxy = new Proxy(source, {
    get: (_, property) => {
      return property
    }
  });

  return proxy as SpecialGenericType<T>;
}

const $ = proxify({
  prop: {},
  a: 'some',
  b: 'random',
  c: 'values',
} as const)

$.prop // typed as the literal value "prop"

const values = [
  $.a,
  $.b,
  $.c
] as const

// values has the type (and value) ["a", "b", "c"];

4 Comments

Almost, but the property keys are unknown ahead of time, it needs to allow specifying any key. For the runtime equivalent, I'm looking for a type that models new Proxy({}, {get: (_, prop) => prop})
If it's helpful to wrap this in a function, it could be: function ($) { // $ is the magic object within here }
Updated my answer. Does that help?
Still no, unfortunately - in your call to proxify, you're passing in an object with the desired keys and then transforming the values into the key names. My issue is that it needs to work with all possible key names, and those key names are not known upfront. As in, the $ type lives inside a library, and consumers of that library need to be able to $.anything and the types still work, without an object listing all possible keys.

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.