1

in non .tsx pages we used to enum like this:

const enumUrl= {
  xxx: [BRAND],
  yyy: [BRAND],
};

In .tsx pages I would like to use enum. So I created:

  enum EnumUrl {
    xxx = "https://example.com/",
    yyy = "https://example.net"
  }

And in JSX:

  Visit <a href={EnumUrl[BRAND}} target="_blank" rel="noopener noreferrer">
    {EnumUrl[BRAND]}
  </a>

However it says:

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'typeof EnumUrl'.ts(7053)

Then I read this possible solution: https://stackoverflow.com/a/41970976/1580094 and did the following:

  enum EnumUrl {
    xxx = "https://example.com/",
    yyy = "https://example.net"
  }

var url : EnumUrl = EnumUrl[BRAND as keyof typeof EnumUrl];

 ...   

 Visit <a href={url[BRAND}} target="_blank" rel="noopener noreferrer">
    {url[BRAND]}
  </a>

Console logs: console.log(url); // https://example.com/ console.log(url[BRAND]); // undefined console.log(BRAND); // xxx

But doing this way, the <a element completely disappears from DOM. No errors.

What am I doing wrong and how can I fix it?

Pikk
  • 2,343
  • 6
  • 25
  • 41

2 Answers2

2

TL;DR an enum doesn't seem to be what you actually want here.

Oh I get that at first blush it seems like an enum: you have a set of URLs. And that set of URLs might actually be an enum, something like:

enum URLs {
  A = "www.foo.com",
  B = "www.bar.com"
}

The problem comes from how you are using the values. Because you are using your "enum" like a map: you're looking up values in it via keys dynamically provided. Javascript/Typescript already has a construct for this purpose (two in fact) so use it, with an enum:

enum Brands {
    'xxx',
    'yyy'
}

// Note that www.foo.com and www.bar.com could be in
// *another* enum, and you could use the URL_MAP to
// connect the two enums. But either way you'll want the
// object for dynamic lookups
const URL_MAP = {
    [Brands.xxx]: "www.foo.com",
    [Brands.yyy]: "www.bar.com",
};

function foo(brand: Brands) {
    return <a href={URL_MAP[brand]} />;
}

Playground

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
  • Thank you. How to apply this directly to JSX without wrapping the `a` element in a function/component? – Pikk Nov 01 '22 at 12:43
  • @Pikk as long as you have a variable of the type of the enum you should be able to use it as a key in the object. You can also define the type of URL_MAP explicitly as `Record` if you want to make it explicit that it is a record type mapping the enum members to URL strings. – Jared Smith Nov 01 '22 at 12:47
  • I am trying to implement the latest. But I get `Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{ 0: string; 1: string; }'.ts(7053)` `BRAND` is being imported from another file. It is a string. – Pikk Nov 02 '22 at 14:29
  • Please check the updated playground to symulate what I have: https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wG4AoUSWOAZxgE8AbJAEzm1zgCJ7m2AtGlyQAdklExa3CuWGj6cAEIIAggDkAInAC8PBgZnlyEgK54lUFKNa04Ab3JxnBAB7v8AGicv8BhvjkAL7G8ooAqggAMgD6ALKqAAq6Dj7OANqW1rYAdO6uALoAXDwA7uU5mBAQOcIg3N4ucJlWNrQ5-sVlFQBGKFC1uA3Bsiau1PBh8ADCIhAAyows7Hp8yzmswABuAAZyEEzQJQAk9pGxCYmZaloFQbI7skA – Pikk Nov 02 '22 at 14:31
  • Your `BRAND` has to be a member of the enum (e.g. `Brands.xxx`), it can't just be a string (in fact the way it's written in your link desugars to sequential integers). If you want string keys, then I stand by my earlier assertion: I really don't think you want an enum here. If the key is coming from *code*, in that case *then* you can use an enum. If it's coming from unknown sources (user input, call over the wire) you can still use an enum but you need to jump through some hoops to verify that the thing is actually a member and I wouldn't bother. – Jared Smith Nov 02 '22 at 14:43
1

Solution found. I just had to use {url}, because the BRAND was already applied in var url : EnumUrl = EnumUrl[BRAND as keyof typeof EnumUrl].

Pikk
  • 2,343
  • 6
  • 25
  • 41