Skip to content

const Type Parameters fail when mapped #54537

Closed
@Peeja

Description

@Peeja

Bug Report

🔎 Search Terms

const Type Parameters, mapped types, self types

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about const Type Parameters (but there's nothing there about them yet)

⏯ Playground Link

Playground link with relevant code

💻 Code

type WithSchema<Self> = {
  // This ensures Self is inferred to be the entire object this type is applied
  // to, while the resulting type leaves the *values* of those keys as
  // `unknown`.
  [K in keyof Self]?: K extends never ? Self[K] : unknown;
} & (("schema" extends keyof Self ? Self["schema"] : {}) extends infer Schema
  ? {
      [K in keyof Schema]?: Schema[K] extends "string"
        ? string
        : Schema[K] extends "number"
        ? number
        : never;
    }
  : never);

declare function doSomething<const Self>(o: WithSchema<Self>): void;

// doSomething's Self isn't automatically `as const`, despite declaring `const Self`.
doSomething({
  schema: {
    name: "string",
    age: "number",
  },
  name: "Alice",
  age: 35,
});

// Explicitly using `as const` works.
doSomething({
  schema: {
    name: "string",
    age: "number",
  },
  name: "Alice",
  age: 35,
} as const);

🙁 Actual behavior

doSomething's Self parameter was not inferred as const.

🙂 Expected behavior

doSomething's Self parameter should be inferred as const, since it's marked as const and inferred from a literal at the call site.

More context

I'm actually working on something more complex than this: typing JSON-LD documents. The core of the issue, though, is that the type of some keys of the object depends on another key (here, schema). I'm doing this using a type parameter which infers as the type of the given object. This uses the same technique described in #52088 (which proposes a more native version using a new keyword).

Currently, the only way to make these types useful is to ask the user of these types to use as const everywhere. Of course, this is less than ideal, which is exactly why const Type Parameters were introduced. But it appears the more complex usage I have breaks that feature, reverting to inferring a widened type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions