Repository navigation
Confusing difference between types and interfaces when intersected with string indexes #24970
Description
Activity
- addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on Jun 14, 2018 RyanCavanaugh commented
on Jun 14, 2018 MemberMore actionsIntersection is a higher-order process that can occur during e.g. generic instantiation; intentionally this process can never create errors.
extendshappens immediately and we do check that you fulfill the base type's contract.Ryan Cavanaugh (@RyanCavanaugh) I'm not sure I completely understand you. Both
bazandfoohere are added viaextends, and bothWithTypeandWithInterfaceare constructed with intersections (&).RyanCavanaugh commented
on Jun 14, 2018 MemberMore actionsOne of the type rules is that
T & Uis assignable toXifTorUis assignable toX.{id: string}, one of the constituents ofWithType, is assignable toIJSonObject`.ok, so - given that
{id: string}is one of the constituents of bothWithTypeandWithInterface, I guess what you're implying is that there is some rule that allowstypes to be assignable tointerfaces that have string index operators, butinterfaces can't be assigned to otherinterfaces that have string index operators, without themselves also defining a matching string index.the above behavior is something I've noticed, I believe, but not seen described anywhere with some convincing reasoning.
- is my description accurate?
- if so, is there a place where I can read more about this, or see it explained in any more detail?
(at the core of these questions is a deep confusion about the minute differences between
typeandinterface, and it seems to be a topic of little in-depth discussion)Reacted by Patrick Desjardins and Ludmi LopezI am confused like Monroe Ekilah (@ekilah) on this one. The interface in that situation has one of the constituents assignable to
IJSONObject, why is it rejected? Your (Ryan) first reply is also confusing since both (type and interface) are using the intersection, and both are a member of a class that extends an interface.RyanCavanaugh commented
on Jun 18, 2018 MemberMore actionsThe spec defines the rules: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md
There is not a single place that explains all emergent behavior. Sometimes we define that X causes Y, and B causes C, and P causes Q, and M causes N, then someone notices that X + B - P + Q isn't identical to X + B - P + M even though M and Q are supposed to be pretty similar - it isn't so much that we specifically designed the X + B - P + M rule and have written down a convincing explanation of why that should be the case, but rather than the initial five propositions are all individually sensible and cannot be changed without making a lot of other things worse.
Ford04 that's an interesting angle, and I really appreciate you sharing it. Your explanation goes above and beyond any of Ryan Cavanaugh (@RyanCavanaugh) 's three "attempts" to half-answer this question or provide some insight after already closing it as if it were obvious. I haven't seen mention of this "implicit index signature" before, but that issue you linked seems to describe a similar issue. Unfortunately it seems like people there have mostly been left to figure it out themselves as well.
For what it's worth, to this day I've never found a good resource that actually describes how types and interfaces differ internally or how we, as external clients of the language, should use them differently, and after using TypeScript for 1.5 years professionally now I think that is simply ridiculous. Here we are, trying to use the language as intended, and when we run across weird behaviors that don't make a lot of sense, the answer is not much more than a "working as intended" label.
Ryan Cavanaugh (@RyanCavanaugh) I invite you and your team back to read this thread all the way through to see if you can give us a little better of an answer, all this time later. Individually, none of your answers above make much sense, and together, they sound fairly incoherent. With all the advances of the type system lately, it surprises me that these types of questions are still left mostly unanswered.
- locked as resolved and limited conversation to collaborators
on Oct 21, 2025
TypeScript Version: 2.8.3
Search Terms: intersection types and interfaces seem to behave differently. Inconsistent 'property 'x' of type 'y' is not assignable to string index type
Code
Expected behavior:
a type error should happen with both,
because
Dateis not inIJSONObject's index signatureActual behavior:
WithTypedoesn't cause an error, even thoughDateshouldn't be allowed.Playground Link: link
Related Issues: possibly #18075 but I'm not really sure.