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 #2491DescriptionTypescript 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 Activitybgever commented on May 21, 2015 +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 jbondc commented on May 31, 2015 +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;
}
jbondc commented on May 31, 2015 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
}
RyanCavanaugh commented on Aug 5, 2015 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)
jbondc commented on Aug 28, 2015 (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. jkillian commented on Nov 16, 2016 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 icholy commented on Dec 14, 2016 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. ChiriVulpes commented on Dec 19, 2016 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 mhegazy commented on Dec 19, 2016 This was broken by #12425. would you mind logging a new issue to allow numeric literals as constraints of mapped types? mattiLeBlanc commented on Mar 3, 2017 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. apetrushin commented on Apr 21, 2017 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 Xample commented on Apr 27, 2017 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 apetrushin commented on Apr 28, 2017 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 mattiLeBlanc commented on Apr 28, 2017 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 nevir commented on Jun 29, 2017 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 aselbie commented on Aug 2, 2017 It appears this is a known regression with a fix on the roadmap: #13042 yordis commented on Dec 8, 2017 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?
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|