GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Intuitive != expected != actual behaviour when combining string and symbol keys · Issue #26470 · microsoft/TypeScript

Intuitive != expected != actual behaviour when combining string and symbol keys #26470

New issue
Copy link
New issue
Copy link
Closed
#44512
Closed
Intuitive != expected != actual behaviour when combining string and symbol keys#26470
#44512
Copy link
Labels
BugA bug in TypeScriptA bug in TypeScriptFix AvailableA PR has been opened for this issueA PR has been opened for this issue
Milestone
Backlog

Description

@yortus
Troy Gerwien (yortus)
opened on Aug 15, 2018
Issue body actions

TypeScript Version: 3.1.0-dev.20180813

Search Terms: string index inference, string key inference

Code

// function foo takes an 'options' object that can have:
// (a) any number of string keys whose values are unary functions
// (b) an optional 'directive' unique symbol key with a unrelated type
const directive = Symbol('directive');
declare function foo<TArg, TRet, TDir>(options:
    {[x in string]: (arg: TArg) => TRet}    // all the string keys are unary functions
    & {[directive]?: TDir}                  // there is an optional 'directive' symbol key
): void;

// CASE 1
// ~~~ERROR~~~ - ... prop 'addOne' incompatible with index signature
//               ... 'x' and 'arg' are incompatible
//               ... 'string' not assignable to 'number'
let case1 = foo({
    [directive]: (x: string) => 'str',
    addOne: (x: number) => x + 1,
    double: (x: number) => x + x,
});

// CASE 2: identical to case 1 except for order of properties
// Compiles OK - infers TArg = number, TRet = number, TDir = (x: string) => string
let case2 = foo({
    addOne: (x: number) => x + 1,
    double: (x: number) => x + x,
    [directive]: (x: string) => 'str',
});

// CASE 3: identical to case 1 except for type of directive
// Compiles OK - infers TArg = number, TRet = number, TDir = string
let case3 = foo({
    [directive]: 'str',
    addOne: (x: number) => x + 1,
    double: (x: number) => x + x,
});

Intuitive expected behaviour:

All three cases compile without errors, with the string and symbol keys typed separately, since the type declaration clearly distinguishes the string keys from the symbol one.

Expected behavior according to #26257 (comment):

That comment suggests that all three cases should fail to compile, since the string index signature covers all symbol keys too, so any symbol key would have to conform to the string index signature, and they don't conform in any of the three cases in the code above.

Actual behavior:

Case 1 fails to compile, but Case 2 and 3 compile fine and in fact do type the string and symbol keys separately as intended by foo's definition.

Playground Link: here

Related Issues:
Taken directly from #26257 (comment). But the issue containing that comment is marked as 'working as intended' so I thought it would be better to open a new issue for this specific case.

Reacted by Matt McFarland, kingces95, John, Trevor and Brian Kim

Activity

Next
  1. yortus commented on Aug 15, 2018

    @yortus
    Troy Gerwien (yortus)
    on Aug 15, 2018
    ContributorAuthor
    More actions

    Another small example from #26257:

    If {[x: string]: T} is intended to apply to all keys (i.e., strings, symbols and numbers), then shouldn't the following fail to compile, since the symbol key doesn't conform to the string index signature?

    const SYM = Symbol();
    declare function foo(obj: {[x: string]: number}): void;
    foo({a: 1, [SYM]: 'sym'});  // Compiles fine
  2. Troy Gerwien (yortus)
    changed the title [-]Type inference problem when combining string and symbol keys[/-] [+]Intuitive != expected != actual behaviour when combining string and symbol keys[/+] on Aug 20, 2018
  3. yortus commented on Aug 20, 2018

    @yortus
    Troy Gerwien (yortus)
    on Aug 20, 2018
    ContributorAuthor
    More actions

    Ryan Cavanaugh (@RyanCavanaugh) would you mind triaging this issue please?

  4. Ryan Cavanaugh (RyanCavanaugh)
    added
    BugA bug in TypeScriptA bug in TypeScript
    on Aug 20, 2018
  5. Ryan Cavanaugh (RyanCavanaugh)
    assigned
    Wesley Wigham (weswigham)
    on Aug 20, 2018
  6. Ryan Cavanaugh (RyanCavanaugh)
    added this to the TypeScript 3.1 milestone on Aug 20, 2018
  7. yortus commented on Aug 20, 2018

    @yortus
    Troy Gerwien (yortus)
    on Aug 20, 2018
    ContributorAuthor
    More actions

    Thanks Ryan Cavanaugh (@RyanCavanaugh). Can we clarify what the bug is here exactly? Is it that the string index seems to include symbol keys under certain conditions, or is it that the string index doesn't include symbol keys under certain conditions?

  8. RyanCavanaugh commented on Aug 20, 2018

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on Aug 20, 2018
    Member
    More actions

    I'm pretty unclear on which behavior is the desired one, which is why I was procrastinating on this one. In any case the property order really shouldn't matter, though.

  9. yortus commented on Aug 20, 2018

    @yortus
    Troy Gerwien (yortus)
    on Aug 20, 2018
    ContributorAuthor
    More actions

    I see. If it turns out that symbols must conform to string indexes, then I hope some consideration is given to how to declare things like foo where we want to type string and symbol keys separately.

    FWIW I can't think of any scenarios where you'd want a strongly-typed symbol property to be constrained by the string index. Symbol-keyed properties usually serve a very specific purpose (think of all the well-known symbols). The type of a symbol-keyed property is usually unrelated to the types of other keys in the same object. Certainly unrelated to string keys, and usually to other symbol-keyed properties too.

  10. Ryan Cavanaugh (RyanCavanaugh)
    modified the milestones: TypeScript 3.1, TypeScript 3.2 on Sep 24, 2018
  11. yortus commented on Nov 6, 2018

    @yortus
    Troy Gerwien (yortus)
    on Nov 6, 2018
    ContributorAuthor
    More actions

    Hey Wesley Wigham (@weswigham), may I ask if there is something holding up the fix for this? Your PR has sat there for a couple of months now. Just wanting to know if this will be addressed by the time v3.2 comes out.

  12. weswigham commented on Nov 6, 2018

    @weswigham
    Wesley Wigham (weswigham)
    on Nov 6, 2018
    Member
    More actions

    3.2 is a no at this point, given it's size, I'd guess. I'm still pushing for it, though. It's just hard to convince the relevant parties that it is both the correct fix (easy) and worth the change (hard). This issue and the others linked in the fix don't make the best case for a change of that size (not many upvotes, little obvious impact), so it's slow going.

  13. yortus commented on Nov 6, 2018

    @yortus
    Troy Gerwien (yortus)
    on Nov 6, 2018
    ContributorAuthor
    More actions

    OK. Well the PR has a much broader scope of changes that what this issue raises. Would a more limited change have more chance of making progress - eg just stop string indexes from constraining symbol keys? The other changes could possibly be approached later if there is demand.

  14. weswigham commented on Nov 6, 2018

    @weswigham
    Wesley Wigham (weswigham)
    on Nov 6, 2018
    Member
    More actions

    So that's not really the issue here. The issue is that mapped types have a concept of mapping symbol keys, but no representation to map them into - so when we do inference, we end up discarding information (which is why the order matters). You need symbol index signatures to fix this.

  15. 26 remaining items

  16. Ryan Cavanaugh (RyanCavanaugh)
    added this to the TypeScript 3.7.1 milestone on Oct 14, 2019
  17. Ryan Cavanaugh (RyanCavanaugh)
    modified the milestones: TypeScript 3.7.1, TypeScript 3.8.0 on Oct 28, 2019
  18. Ryan Cavanaugh (RyanCavanaugh)
    modified the milestones: TypeScript 3.8.0, TypeScript 3.8.1 on Jan 8, 2020
  19. Ryan Cavanaugh (RyanCavanaugh)
    added
    BugA bug in TypeScriptA bug in TypeScript
    and removed
    Fix AvailableA PR has been opened for this issueA PR has been opened for this issue
    InvestigatingIs in active investigationIs in active investigation
    SuggestionAn idea for TypeScriptAn idea for TypeScript
    on Jan 23, 2020
  20. Ryan Cavanaugh (RyanCavanaugh)
    modified the milestones: TypeScript 3.8.1, Backlog on Jan 23, 2020
  21. Ryan Cavanaugh (RyanCavanaugh)
    unassigned
    Wesley Wigham (weswigham)
    on Jan 23, 2020
  22. TypeScript Bot (typescript-bot)
    added
    Fix AvailableA PR has been opened for this issueA PR has been opened for this issue
    on Nov 5, 2020
  23. Anders Hejlsberg (ahejlsberg)
    closed this as completedin #44512on Jun 21, 2021
  24. microsoft
    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

Assignees

No one assigned

    Labels

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

    Type

    No type

    Projects

    No projects

      Milestone

      • BacklogNo due date

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.