1

I am trying to implement an Enum - composed of string - in an attempt to make my code more robust.

The method addSkills() received (among others) a skills parameters which is a string array.

Here is the test code :

    it('should record skills into database', async () => {
      const id = '19'
      const token = 'a64a47cc4c3c6282c229df78aab373c3d0dd94c4'
      const newSkill = 'Friendly'
      await service.addSkills(id, token, [newSkill])
      const recordedSkills = service.getCandidateSkills(id)
      expect(recordedSkills).toContain('Friendly')
    })
  })

Here is the temporary production code :

async addSkills(
    id: string,
    token: string,
    skills: SoftSkillsEnum[]
  ): Promise<[] | null> {
    throw new HttpException('Unknown resource', HttpStatus.NOT_FOUND)
  }

export enum SoftSkillsEnum {
  CREATIVE = 'Creative',
  FUNNY = 'Funny',
  EMPATHETIC = 'Empathetic',
  EXPLORER = 'Explorer',
  SPORTY = 'Sporty',
  SUPER_SMART = 'Super Smart',
  FRIENDLY = 'Friendly',
}

The test code trigger the Typescript error on line 5 of the test code: TS2322: Type '"Friendly"' is not assignable to type 'SoftSkillsEnum'.

As far as I understand it, Typescript make a difference between a string and an enum composed of string. But I don't want my method to accept any string, the input should match a predefined list of string (the predefined "softsSkills").

Anyway to make it work or I must give up my enum implementation attempt?

A Mehmeto
  • 1,594
  • 3
  • 22
  • 37

1 Answers1

2

Not sure why you want the enum, but if you want to limit the skills to a subset of strings, you can use union type e.g.

export type SoftSkills = 'Creative' | 'Funny' | ... | 'Friendly';

...

async addSkills(
    id: string,
    token: string,
    skills: SoftSkills[]
  ): Promise<[] | null> {
    throw new HttpException('Unknown resource', HttpStatus.NOT_FOUND)
  }

    it('should record skills into database', async () => {
      const id = '19'
      const token = 'a64a47cc4c3c6282c229df78aab373c3d0dd94c4'
      const newSkill = 'Friendly'
      await service.addSkills(id, token, [newSkill])
      const recordedSkills = service.getCandidateSkills(id)
      expect(recordedSkills).toContain('')
    })

If you need runtime access to the list (e.g. for validation), or you are sure that you need the enum, you can get the keys of the enum:

type SoftSkills = keyof(typeof SoftSkillsEnum);

...

async addSkills(
    id: string,
    token: string,
    skills: SoftSkills[]
  ): Promise<[] | null> {
    throw new HttpException('Unknown resource', HttpStatus.NOT_FOUND)
  }

    it('should record skills into database', async () => {
      const id = '19'
      const token = 'a64a47cc4c3c6282c229df78aab373c3d0dd94c4'
      const newSkill = 'FRIENDLY'
      await service.addSkills(id, token, [newSkill])
      const recordedSkills = service.getCandidateSkills(id)
      expect(recordedSkills).toContain('')
    })

But beware that now SoftSkills is a list of skills in ALL CAPS, since that was how the enum was defined.

Or maybe just actually use the enum for your newSkill?

...
      const newSkill = SoftSkillsEnum.FRIENDLY
      await service.addSkills(id, token, [newSkill])
...
LeoYulinLi
  • 129
  • 6
  • Thank you very much for this very informative answer. But isn't one of the purpose of the enum to "limit the skills to a subset of strings" (for instance)? – A Mehmeto Sep 09 '20 at 01:55
  • From the TypeScript documentation itself : "Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. " It introduce doubt about what I should use. I am happy to have your thoughts. – A Mehmeto Sep 09 '20 at 02:07
  • I opted for a type union instead of an enum. Thanks. – A Mehmeto Sep 09 '20 at 04:16
  • @AMehmeto I would say enums define sets of "options", not necessarily strings. I added a suggestion to just use a enum directly, but if `newSkill` is some user input (which is a string), that won't really work. I mainly use enum for the "named constants" purpose, e.g. LEFT = 0b1, RIGHT = 0b10, etc. where the number themselves are really hard to understand without some context. Here is a post that I found useful on this topic: https://stackoverflow.com/a/40279394 – LeoYulinLi Sep 09 '20 at 04:21