Reputation: 2164
I defined an Enum to clarify APIs request status:
const enum Errcode{
Ok=0,
Error=1,
AccessDeny=201,
PostsNotFound=202,
TagNotFound=203,
//...
}
type SuccessErrcode =Errcode.Ok;
type NotFoundError =Errcode.PostsNotFound|Errcode.TagNotFound;
type ErrorErrcode=/* there */;
How can I define the ErrorErrcode
that means all items of Errcode except Errcode.Ok (and it should include all items of NotFoundError)?
I can't define the more granular types and Union them likes this:
enum SuccessErrcode {
Ok =0,
}
enum NotFoundErrcode {
PostsNotFound=202,
TagNotFound=203,
}
enum ErrorErrcode {
Error=1,
}
type Errcode =SuccessErrcode|NotFoundError|SuccessErrcode;
If I do this, I will can't use Errcode.xxx
- for use a code, I must to know where it be assigned of.(e.g. from Errcode.TagNotFound
to NotFoundError.TagNotFound
). And consider that - when there have TagErrcode
and NotFoundErrcode
, the TagNotFound=203
will be defined twice.
Upvotes: 143
Views: 100652
Reputation: 27
enum UserRole {
ADMIN='ADMIN',
USER=''USER,
CLIENT='CLIENT'
STUDENT='STUDENT'
}
userRoles = UserRole
this.userRoles.delete('ADMIN')
this.userRoles.delete('USER')
Upvotes: 0
Reputation: 8978
As of TypeScript 2.8 and the addition of conditional types, you can use the built-in Exclude
to exclude certain enum values:
const enum Errcode {
Ok=0,
Error=1,
AccessDeny=201,
PostsNotFound=202,
TagNotFound=203,
//...
}
type SuccessErrcode = Errcode.Ok;
type NotFoundError = Errcode.PostsNotFound|Errcode.TagNotFound;
type ErrorErrcode = Exclude<Errcode, Errcode.Ok>;
Upvotes: 231
Reputation: 631
If you want the "typed" version of the above (plus some refinements):
enum Country {
Afghanistan = 'Afghanistan',
Albania = 'Albania',
Guam = 'Guam',
UnitedStates = 'United States'
}
const usAndIslands: Country[] = [Country.Guam, Country.UnitedStates];
const nonUsCountries: { [x: string]: string | Country } = Object.entries(Country)
.filter((country: [string, string | number]): boolean =>
typeof country[1] === 'number' && !usAndIslands.includes(country[1]))
.reduce((dict: {}, [key, value]: [string, string | Country): { [x: string]: string | Country } =>
Object.assign(dict, { [key]: value }), {});
console.log(nonUsCountries);
And if you want the result to be a Country[]
, you would use this:
const nonUsCountries: Country[] = Object.entries(Country)
.filter((country: [string, string | number]): boolean =>
typeof country[1] === 'number' && !usAndIslands.includes(country[1]))
.map(([, value]: [string, string | Country): Country => val as Country);
And here is an abstracted function you can use with any numeric enum:
/**
* Returns an array of enum values given an enum and disallowed values.
*
* @param myEnum The enum name.
* @param disallowedValues An array of values of myEnum that should not be returned.
*
* @return An array of all myEnum values without the disallowedValues.
*/
export const numericEnumFilterOut: Function =
<R extends number, T extends {[key: string]: R}>(myEnum: T, disallowedValues: R[]): R[] =>
Object.entries(myEnum)
.filter((type: [string, string | R]): boolean =>
typeof type[1] === 'number' && !disallowedValues.includes(type[1]))
.map((type: [string, R]): [string, R] => type as [string, R])
.map(([, value]: [string, R]): R => value);
Usage:
const nonUsCountries: Country[] =
numericEnumFilterOut(Country, [Country.Guam, Country.UnitedStates]);
console.log(nonUseCountries);
Upvotes: 0
Reputation: 37668
This took quite a bit of time to figure out. There really has not been an answer to this question in all its incarnations that worked for me. I needed to be able to treat the new value set the same way as the original enum, i.e. populate selection lists with it etc.
Then I was stuck for a bit on the fact that Object.entries()
produces an array of arrays from a dictionary, and I had to convert this back into a dictionary so that my existing code continued to work with either type.
reduce()
to the rescue!
Here is my solution (credit goes to Jake Holzinger's answer to this question):
enum Countries {
UnitedStates = 'United States',
Afghanistan = 'Afghanistan',
Albania = 'Albania'}
const UsAndIslands = [
Countries.UnitedStates];
const NonUsCountries = Object.entries(Countries)
.filter((country) => !UsAndIslands.includes(country[1]))
.reduce((dict, [key, value]) => Object.assign(dict, { [key]: value }), {});
console.log("Countries", Countries);
console.log("NonUsCountries", NonUsCountries);
Upvotes: 3
Reputation: 14485
You would first define the more granular types. Perhaps something like this:
enum ErrorCode {
Error = 1,
AccessDeny = 201,
PostsNotFound = 202,
TagNotFound = 203,
}
enum SuccessCode {
Ok = 0
}
You can then define a Union Type to be either a SuccessCode
or a ErrorCode
:
type ResultCode = ErrorCode | SuccessCode;
which you can then use like this:
const myResult1: ResultCode = ErrorCode.AccessDeny;
const myResult2: ResultCode = SuccessCode.Ok;
Upvotes: 11