enum isEnum mapped-types conditional-types enum-test extends-enum
Rephrased from : https://stackoverflow.com/questions/50452032/typescript-enum-type-check-for-conditional-types
Here's what I kinda want, but it is not syntactically valid:
enum Features {
"A" = 1,
"B" = 2,
"C" = 2
}
type EnumOrString<T> = T extends enum
? T | keyof T
: T
declare function getData(featureFilter: EnumOrString<typeof Features>[]): Features[]
getData takes an array of the enum values or the enum keys but returns only the enum values.
I also would want to extend this to mapped types similar to DeepPartial so that any nested enums all get this treatment - without having to have separate hierarchies of types partitioned by Request and Response. Example on Playground
I make calls to restful services that accept enum values as either the number value OR the string key, but the services always return just the number value. I could ignore the ability to send strings, but some code would have to be rewritten because it happens to cache values by these key names.
My suggestion meets these guidelines:
I am not sure i understand what you mean by keyof T in the above example.. keyof Feature is the same as keyof number, which is a list of "toString" | "toExponential" ..., so i am guessing Feature | "toString" is not what you want from this type..
I think you meant keyof typeof Feature, and for that, you have to remember to pass in the value type at use site, and if you are doing this for enums, why need to use a conditional type?
Fixed that in the example. The case I'm going for is like this though:
export type DeepEnumish<T> =
T extends any[] ? DeepEnumishArray<T[number]> :
T extends enum ? T | keyof T :
T extends object ? DeepEnumishObject<T> :
T;
export interface DeepEnumishArray<T> extends Array<DeepEnumish<T>> {}
export type DeepEnumishObject<T> = {
[P in keyof T]: DeepEnumish<T[P]>;
}
declare function roundtripPayload(criteria : DeepEnumish<Payload>): Payload
Where the nested enum members of Payload can be sent as numbers or strings, and will be returned from the server as numbers certainly.
this line still does not make much sense still.. T extends enum ? T | keyof T : if T is an enum type, keyof T is keyof number | keyof string.. which is not what you want if i understand correctly..
I am guessing you want keyof typeof e, but to do that, you need the value reference, which you do not have.
This is such a common confusion (class and enum introducing both a named type and a named value where the named value is not of the named type) that I wonder if there's any use for a feature request that lets people get from the named type to the type of the named value. Something like this for enums:
enum MyEnum { A, B }
type TypeofMyEnum = EnumTypeof<MyEnum>; // typeof MyEnum
I'm thinking of something like the following synthetic enum code, which extends the type of each element of the enumeration with a design-time-only brand that points back to the enum object:
type EnumBrand<E> = { __enum: E };
type EnumTypeof<E extends EnumBrand<any>> = E['__enum'];
namespace MyEnum {
const brand = <T>(x: T) => x as T & EnumBrand<typeof MyEnum>;
enum _MyEnum { A, B }
// ignoring reverse mapping as well as bitwise craziness
export const A = brand(_MyEnum.A);
export type A = typeof A;
export const B = brand(_MyEnum.B);
export type B = typeof B;
}
type MyEnum = typeof MyEnum[keyof typeof MyEnum];
Then the following works:
type TypeofMyEnum = EnumTypeof<MyEnum>;
and checking for the brand would meet the "detect an enum" requirement if needed, also:
type IsEnum<T> = T extends EnumBrand<any> ? true : false
I don't like phantom properties that don't exist at runtime, so maybe some other way would work? Thoughts?
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.