Skip to content

Situations where object literal type inference fails #36549

@harrysolovay

Description

@harrysolovay

Search Terms: "infer", "object", "literal", "key", "value", "entry", "entries", "type", "signature", "keyof"

While digging into the keyofStringsOnly flag, I realized the following.

Code

Let's say we have this object literal:

const obj = {
  a: 1,
  b: true,
  c: "yo",
};

It has a finite number of possible keys/values/entries. In many cases, this is true for non-literals as well:

interface Obj { a: 1; b: true; c: "yo"; }
declare function getObj(): Obj;
// we can be certain that `obj` will have the `Obj` signature
const obj = getObj();

Let's try to get the key, value and entry types from obj.

// expected signature of `[string, 1 | true | "yo"][]`
// actual signature of `[string, string | number | boolean][]`
const entries = Object.entries(obj);

// expected signature of `"a" | "b" | "c"`
// actual signature of `"a" | "b" | "c"`
type KeyOfType = keyof typeof obj;

// expected signature of `{ a: 1; b: true; c: "yo"; }`
// actual signature of `{ a: number; b: boolean; c: string; }`
type ObjType = typeof obj;

// expected signature of `1 | true | "yo"`
// actual signature of `string | number | boolean`
type ValueType = ObjType[KeyOfType];

I've played around with my TSConfig to see if I can get the correct behavior. keyofStringsOnly nor strictMode make a difference.

In discussions such as #35745, some users state that it's a 3rd-party library's responsibility to correct this (IMO seemingly-faulty) inference. A custom entries function––for example––could make use of the Exclude utility type. While getting the correct signature is certainly possible in the language, I believe it should––in the cases above––be the default.

Please let me know if I'm missing something, or haven't the right configuration. Any help would be greatly appreciated. Thank you!

Playground Link:
here

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions