Skip to content

When creating a mapped type of an indexed type it extends too liberal #32484

Closed

Description

@jauco

TypeScript Version: 3.6.0-dev.20190719

Search Terms:
Mapped types extends Index types

Code

type constr<Source, Tgt> = {[K in keyof Source]: string } &Pick<Tgt, Exclude<keyof Tgt, keyof Source>> 


type s = constr<{}, {
  [key: string]: {
      a: string;
  };
}>
declare const q: s
q["asd"].a.substr(1) //see: a is a string
q["asd"].b  //and of course b does not exist (this line will have an error)

//but I expect the following line to error as well
const d: {[key: string]: {a: string, b: string}} = q
//and verify to be "no" (instead it is "yes")
type verify = s extends {[key: string]: {a: string, b: string}} ? "yes" : "no"

// the error _is_ shown if you construct a (seemingly identical) type by hand
type sManual =  {} & Pick<{
    [key: string]: {
        a: string;
    };
}, string | number>
declare const qManual: sManual
// see: error here
const dManual: {[key: string]: {a: string, b: string}} = qManual

//the error is also shown if I replace the indexed type with an actual property
type s2 = constr<{}, {
  asd: {
      a: string;
  };
}>
declare const q2: s2
q2.asd.a.substr(1) //this is the same
q2.asd.b //this also


//But this is now an error (as it should be)
const d2: {asd: {a: string, b: string}} = q2

//and this is "no" (as it should be)
type verify2 = s2 extends {asd: {a: string, b: string}} ? "yes" : "no"

Expected behavior:
As described inline. I do not think q should be assignable to d
Actual behavior:
q is assignable to d

Playground Link: http://www.typescriptlang.org/play/#code/C4TwDgpgBAxg9gOwM7AE4B4DKcCuqYQA0UAKgObAB8UAvFAN4DaA0lAJYJQDWEIcAZlGx4CAXQBcUFKg5koAXygAyAApsYXdOWDEAogA8YAGxwATCOh59B24lYFDc+CJWoAoD6EhTasRNPR6eWJ6NygoRitJaVkJBjDwxIBDaLRZAG4E+Uz5SjdzYyTUaHhkYCgAR2i3CsYAIiSkUzrRADok1qQcACNpAAoARgBKKAB6UaQICEkk9iQoWZiEMhr6xua27vDxpIRTKAd4PEmoLdM4CHmEOHKIfTYUKD7gAAsHqCMOaAB3NiMjKAvJIAN2guygEFQqDgqCGHnG3Rw5QAkhD9JAYOVXtB+HB-nBfssPl8oMA4BCoTCFvNvhB-m5So9TJImFEpGllnF6Cl2TJlsRuqk+WR5Io6BU3Ds9lBQTJ+CBSeTutA6tc6k8OCgIEl9mxyu86iBLnU4V5oLK2PLfPM7sAIHt5qzeELYiyeUsyAKXctRVAAPxQQ3GqCSVVwOrw0akl7QSHQ1BQAD6D0T0eh304lqgfBwfjKqBwmIWT0mEAAtrIjAq2OYEMB1EkjCMzacFUC9m4W0gALK7HCN3wMRRKKBqDSBBLhSLO3mu+KJBcLb1kTIL7JuYKzokAHygCBwZeVqDyBSMRRK-nKFV7+8b0Rv-aMkqjpckcapMeKDMvUFMD7vDDTiAy5cu6HKeqcy6+uK-5Ps+yKCKixRgGeBDRtAHDmPoED7C2vyvAsnBJJij5QGA0KQKgoCduA0BIAATL4jJoIEm6hOE6wspOyTLquCg5CeECFMUeaPBU9HRPRNT0e0TTtJ0PT9MMYyjK87zvNiUhJGWEDSbJpitFs4xqfMjZIHAHjPgAQki0bqVcBKERS8ZPI07DlEgLy4EY+zKnCzG-hJDCccFy5eluIpipUUnPrsuFvPMBpqq5iUeV5OA+acECmrRMqQpaICMXQDFonaDrBU0bphZBEW+gGQZIOqoZqm4QA

Related Issues: Sorry, no. But as evidenced by my search terms I have some trouble finding the right words to describe the bug

Activity

  1. ahejlsberg commented on Oct 17, 2019

    @ahejlsberg
    Member

    Simple repro:

    declare let s: { a: string } & { b: number };
    declare let t: { [key: string]: string };
    t = s;  // No error!

    Surprisingly we don't error on the above, but we definitely should. Specifically, when relating an intersection type to a type with an index signature, we need to check that all constituents in the intersection type are related to the index signature. We currently only check that some constituent is related.

  2. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions