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 — Index signature parameter type should allow for enums · Issue #2491 · microsoft/TypeScript

Index signature parameter type should allow for enums #2491

New issue
Copy link
New issue
Copy link
Closed
Closed
Index signature parameter type should allow for enums#2491
Copy link
Labels
Fix AvailableA PR has been opened for this issueA PR has been opened for this issueSuggestionAn idea for TypeScriptAn idea for TypeScript
Milestone
TypeScript 2.1.4

Description

@jhlange
Joshua Lange (jhlange)
opened on Mar 25, 2015
Issue body actions

Typescript requires that enums have number value types (hopefully soon, this will also include string value types).

Attempting to use an enum as a key type for a hash results in this error: "Index signature parameter type much be 'string' or 'number' ".-- An enum is actually a number type.-- This shouldn't be an error.

Enums are a convenient way of defining the domain of number and string value types, in cases such as

export interface UserInterfaceColors {
    [index: UserInterfaceElement]: ColorInfo;
}
export interface ColorInfo {
    r: number;
    g: number;
    b: number;
    a: number;
}
export enum UserInterfaceElement {
    ActiveTitleBar = 0,
    InactiveTitleBar = 1,
}
Reacted by Greg Bódi, Michał Stocki, Mateusz Kocz, resal81, Gabriele, Mark Crawshaw, Christian Ulmann, Ethan Breder, Adi Dahiya, Graham Penrose and 289 more
Reacted by Ron Newcomb, Kat, João Carlos, Tom Riglar, apollocoder, Moved to @ad-si, mareknab, Priit Kallas, Joshua Jolley, Mo and 28 more

Activity

Next
  1. Mohamed Hegazy (mhegazy)
    added
    SuggestionAn idea for TypeScriptAn idea for TypeScript
    on Apr 2, 2015
  2. Jason Freeman (JsonFreeman)
    modified the milestone: TypeScript 2.0 on Apr 13, 2015
  3. bgever commented on May 21, 2015

    @bgever
    Bart Verkoeijen (bgever)
    on May 21, 2015
    More actions

    +1, this is a great way for type-safe dictionaries.

    Reacted by Nicolas Gramlich, Rizky Luthfianto, Keegan Farley, rpdeshaies, Dave Landis, Jonas Wouters, Corbin Crutchley, Dimitry and David Drew
  4. jbondc commented on May 31, 2015

    @jbondc
    Jon (jbondc)
    on May 31, 2015
    Contributor
    More actions

    +1

    If the TS team embraces 'set types' #3105, this would work too:

    interface SomeArrayLikeThing {
        [index: 0...255]: number;
    }
    
    enum foo {
     [prop: string]: 0...255
     a,
     b,
     c
    }
    
    interface SomeArrayLikeThingByEnum {
        [index: foo]: number;
    }
    
    Reacted by Anton Kosiak
  5. jbondc commented on May 31, 2015

    @jbondc
    Jon (jbondc)
    on May 31, 2015
    Contributor
    More actions

    Would likely require at the minimum in the compiler something like:

    export interface ObjectIndex {
           valueType: Type        // any
           keyType?: Type         // string|number or any subset type
    }
    export interface ResolvedType extends ObjectType, UnionType {
           members: SymbolTable;              // Properties by name
           properties: Symbol[];              // Properties
           callSignatures: Signature[];       // Call signatures of type
           constructSignatures: Signature[];  // Construct signatures of type
           stringIndex?: ObjectIndex;            // String index
           numberIndex?: ObjectIndex;        // Numeric index
    }
    
  6. Ryan Cavanaugh (RyanCavanaugh)
    added
    In DiscussionNot yet reached consensusNot yet reached consensus
    on Jul 14, 2015
  7. Ryan Cavanaugh (RyanCavanaugh)
    added
    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.
    and removed
    In DiscussionNot yet reached consensusNot yet reached consensus
    on Aug 5, 2015
  8. RyanCavanaugh commented on Aug 5, 2015

    @RyanCavanaugh
    Ryan Cavanaugh (RyanCavanaugh)
    on Aug 5, 2015
    Member
    More actions

    This does seem very useful. Going back to the original example, we had some questions about the intended semantics. Given some types:

    enum Color { red, green, blue }
    enum Size { small, medium, large }
    interface Alpha {
      [c: Color]: string;
    }
    interface Beta {
      [c: Size]: string;
    }
    interface Gamma {
      [c: number]: string;
    }
    interface Delta {
      [c: Color]: string;
      [c: Size]: string;
    }

    Obvious things:

    • You can't index an Alpha by a Size

    Non-obvious things:

    • Is Alpha assignable to Beta ?
    • Is Gamma assignable to Alpha ? Vice versa?
    • Can I index an Alpha by a number ?
    • Is Delta a legal declaration? (strongly leaning toward no)
  9. jbondc commented on Aug 28, 2015

    @jbondc
    Jon (jbondc)
    on Aug 28, 2015
    Contributor
    More actions

    (a)

    Is Alpha assignable to Beta ?
    Is Delta a legal declaration?

    No

    (b)

    Can I index an Alpha by a number ?
    Is Gamma assignable to Alpha ? Vice versa?

    Yes (unfortunately), follow isTypeAssignableTo()

    const enum Color { red, green, blue }
    let a: number;
    let b: Color;
    a = 4;
    b = 4; // unfortunately (c)
    
    interface Alpha {
      [c: Color]: string;
    }
    let c: Alpha;
    c[Color.red];
    c[0];
    c[4]; // unfortunately (c)
    

    I'd be happy if (c) changed eventually so that const enums only accept constants or types within their range of values.

  10. Ryan Cavanaugh (RyanCavanaugh)
    added
    In DiscussionNot yet reached consensusNot yet reached consensus
    and removed
    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.
    on Aug 28, 2015
  11. Ryan Cavanaugh (RyanCavanaugh)
    added
    DeclinedThe issue was declined as something which matches the TypeScript visionThe issue was declined as something which matches the TypeScript vision
    Too ComplexAn issue which adding support for may be too complex for the value it addsAn issue which adding support for may be too complex for the value it adds
    on Oct 5, 2015
  12. 24 remaining items

  13. jkillian commented on Nov 16, 2016

    @jkillian
    Jason Killian (jkillian)
    on Nov 16, 2016
    More actions

    Mohamed Hegazy (@mhegazy): it seems like it might be a little trickier than that in practice?

    export enum MyEnum {
        First = 0,
        Second = 1,
    }
    
    export type EnumMap = {
        [P in MyEnum]: string;
    }
    
    // [ts] Type '{ [x: number]: string; }' is not assignable to type 'EnumMap'.
    //      Property '0' is missing in type '{ [x: number]: string; }'.
    const doesntWork: EnumMap = {
        [MyEnum.First]: "first",
        [MyEnum.Second]: "second",
    };
    
    const works: EnumMap = {
        0: "first",
        1: "second",
    };
    
    // but then this is allowed, should it be?
    works["foo"] = "bar";
    // but then: 
    // [ts] Property 'foo' does not exist on type 'EnumMap'.
    type test = typeof works["foo"]
    Reacted by Laurens Rietveld, Maxim Kulikov, Chris Krycho, Stephen M, Neculai Andrei, Prashant Khurana, Alvis Tang, Patrick Lienau, Igor Soloydenko, Esteban Gehring and 3 more
  14. icholy commented on Dec 14, 2016

    @icholy
    Ilia Choly (icholy)
    on Dec 14, 2016
    More actions

    You can use any type as the key for Map and if you really want type safe object keys, you can wrap it.

    class DictValues<V> {
        [key: string]: V;
        [key: number]: V;
    }
    
    interface ToStringer {
      toString(): string;
    }
    
    class Dict<K extends ToStringer, V> {
      private _values: DictValues<V> = Object.create(null);
    
      get(key: K): V {
        return this._values[key.toString()];
      }
    
      set(key: K, value: V): void {
        this._values[key.toString()] = value;
      }
    
      has(key: K): boolean {
        return this._values.hasOwnProperty(key.toString());
      }
    
      values(): DictValues<V> {
        return this._values;
      }
    }
    Reacted by Aluan Haddad, Laurens Rietveld, Maxim Kulikov, Chris Krycho, Alexander Trauzzi, Oscar Porres, Vinicius Fortuna and Daniel K.
  15. ChiriVulpes commented on Dec 19, 2016

    @ChiriVulpes
    Chiri Vulpes (ChiriVulpes)
    on Dec 19, 2016
    Contributor
    More actions

    Mohamed Hegazy (@mhegazy): I get Type 'UserInterfaceColors' is not assignable to type 'string' when using the code that should work:

    export type UserInterfaceColors = {
        [P in UserInterfaceElement]: ColorInfo;
    }

    Coupled with the bits Jason Killian (@jkillian) mentioned makes me think this should be reopened (or at least the Fixed tag removed)

    Reacted by Laurens Rietveld, Lauri Lehmijoki, Luis Belloch, Maxim Kulikov, Victor Ermolaev, Patrick Lee, esc-co, João Carlos, Donatas Uziela, Garth Kidd and 16 more
  16. mhegazy commented on Dec 19, 2016

    @mhegazy
    Mohamed Hegazy (mhegazy)
    on Dec 19, 2016
    Contributor
    More actions

    This was broken by #12425. would you mind logging a new issue to allow numeric literals as constraints of mapped types?

  17. Mohamed Hegazy (mhegazy)
    removed
    FixedA PR has been merged for this issueA PR has been merged for this issue
    on Feb 6, 2017
  18. mattiLeBlanc commented on Mar 3, 2017

    @mattiLeBlanc
    Matti LeBlanc (mattiLeBlanc)
    on Mar 3, 2017
    More actions

    Hi, I would also benefit from being able to use a declared type as index, so that I can restrict which kind of indexes are being used.

    For example:

    declare type validationTypes = 'email' | 'number' | 'abn';
    
    interface IField {
      label:                string;
      model:                string;
      type:                 fieldType;
      placeholder?:         string;
      addon?:               string;
    }
    
    interface IEmailValidation {
      email:              string;
    }
    interface IRequiredValidation {
      required:             string;
    }
    
    
    interface IEmailField extends IField {
      type:                'email';
      validation:        IDictionary<IEmailValidation | IRequiredValidation>
    }
    

    What I try to achieve is that the validation will be a dictionary and has the key 'email' and the value type of string, and a required validation.

    A text field would only have Required validation.

    The Javascript object looks like this:

    const emailField =        {
              "label":                "Email Address",
              "model":               "emailaddress",
              "type":                 "email",
              "placeholder":          "Please enter an email address",
              "validation": {
                "required":          "An email address is required",
                "email":              "Please enter a valid email address"
              }
            }
    

    Right now I can only allow all possible validations but I can't restrict the set of validations per field type. This is because of the index must to be string or number restriction.

    If it would be possible to define a dictionary like this:

    export interface IDictionary<K,V> {
      [index: key]: V;
    }
    then K could be a declare type of 'email' | 'required' for an email field and only 'required' for a text field.
    

    Any thoughts?

    Reacted by Pedro Filipe, Anatolii Obitskyi, apetrushin, AJP / James Phillips, Jacob Eggers and Daniel K.
  19. apetrushin commented on Apr 21, 2017

    @apetrushin
    apetrushin
    on Apr 21, 2017
    More actions

    This seems to be quite frequent pattern, would be nice to support it.

    type keys = 'a' | 'b' | 'c'
    let map: { [key: keys]: string } = {}
    
    Reacted by Amir Arad, zhang.ky, Jacob Eggers, Vinicius Fortuna, Buleandra Cristian, Rohan Rogers, Cory Noonan, PSeitz, Maks Rafalko, roscaj and 13 more
  20. Xample commented on Apr 27, 2017

    @Xample
    Flavien Volken (Xample)
    on Apr 27, 2017
    More actions

    apetrushin you can use "in" for this

    type keys = 'a' | 'b';
    let anObject: { 
    	[index in keys]: string;
    }
    anObject.a = "correct";
    anObject.t = "error";
    
    Reacted by SlurpTheo, Garth Kidd, Javier Sánchez - Marín, Cyan, Anton Fedchenko, ziga, Diego Maninetti, Misha Khazov, Matan Hafuta, thiagoh and 3 more
    Reacted by Michał Miszczyszyn, Egor Komarov, Amit Beckenstein and Kevin Groat
    Reacted by Garth Kidd, Thomas Wolf, Gábor IMRE, Mosh Feu, thiagoh and Ivan P
  21. apetrushin commented on Apr 28, 2017

    @apetrushin
    apetrushin
    on Apr 28, 2017
    More actions

    Thanks, but it's still allows to do anObject['non-existing-key'] = 'value'

    Reacted by AJP / James Phillips, Kewin Dousse, George Evstigneev, PSeitz, Michael Joseph Rosenthal, Antoine ESTEVE, Amit Beckenstein, Kevin Groat and Alex0007
  22. mattiLeBlanc commented on Apr 28, 2017

    @mattiLeBlanc
    Matti LeBlanc (mattiLeBlanc)
    on Apr 28, 2017
    More actions

    Have a look at my post just above. That would be an awesome addition. Right now we can only defined the index of a dictionary to be of a string but not restrict to a list of string types.
    Any change this can become a feature?

    Reacted by Kewin Dousse and Nir Yosef
  23. nevir commented on Jun 29, 2017

    @nevir
    Ian MacLeod (nevir)
    on Jun 29, 2017
    More actions

    This appears broken again as of TS 2.4 (2.x?)

    enum Things { ONE, TWO }
    // Error: Type 'Things' is not assignable to type 'string'. 
    type ThingMap = {[TKey in Things]: boolean};
    Reacted by thiagoh and Lucas Mafra
    Reacted by Amit Beckenstein, wildex999, Ethan Mick, Cory Li, Aleksi Pekkala, Cade, Tony Skidmore, Sam Maddock, Ian Copp, Jacob Eggers and 17 more
    Reacted by thiagoh and Lucas Mafra
  24. aselbie commented on Aug 2, 2017

    @aselbie
    Andrew Selbie (aselbie)
    on Aug 2, 2017
    More actions

    It appears this is a known regression with a fix on the roadmap: #13042

    Reacted by Matt
  25. yordis commented on Dec 8, 2017

    @yordis
    Yordis Prieto (yordis)
    on Dec 8, 2017
    More actions

    Ian MacLeod (@nevir) I am using 2.6 and it is working fine for me but because I match the enum keys to some string

    enum Things { ONE = 'one', TWO = 'two' }

    Should be that the default behavior? or should be just doing the enum without any mapping?

    Reacted by ZpdDG4gta
  26. microsoft
    locked and limited conversation to collaborators on Jun 18, 2018
  27. 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
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

    Fix AvailableA PR has been opened for this issueA PR has been opened for this issueSuggestionAn idea for TypeScriptAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      • TypeScript 2.1.4

      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.