Búsqueda de sitios web

En TypeScript, `number` se puede asignar a `enum`, pero `string` no. ¿Por qué?


En TypeScript, number se puede asignar a enum, pero string no... se ve raro. ¿Por qué funciona así?

¿Y hay algunas opciones de ts relacionadas con esto?

enum MixEnum {
  HELLO = 'hello',
  WORLD = 2,
}

const ms1: MixEnum = String('foo'); // Type 'string' is not assignable to type 'MixEnum'.
const ms2: MixEnum = String('hello'); // Type 'string' is not assignable to type 'MixEnum'.

const mn1: MixEnum = Math.random(); // no error
const mn2: MixEnum = Number('99999'); // no error
const mn3: MixEnum = MixEnum.WORLD + 100; // no error

https://www.typescriptlang.org/play?#code/KYOwrgtgBAcpCi5oG8BQUoAl4BkcHkoBeKARgBp0oB1fAJRwBFioAmSgX1VQGMB7EAGcALlBAhSALlgIkLALIBDYQAsAdACdFIACZ8IACgCUAbl4CRYkK2lwIiSCzsAjYBoMByAJw+fH0+ZCouIAzNLyAJYAHg7QJHaxarQMzADUZAAMGWaoAPT5BYUF3KCOkTFyaBjYeIQkHirAADZNfB6UGMlMLOyoXIGWEBLh0bEKyupauvrGZvxBUEM2UOVj8ZCu7t6+Xv5zFqJDYSujciSrSEn03emkWTnzg4JSJxWOJADKwhoRIADmngAZnw2gFHodBMsLu8oF8fv9PI0WqCzEA

Respuesta #1

Los enumerados numéricos de TypeScript se comportan de maneras un poco extrañas. Este comportamiento, donde un enum con cualquier miembro numérico trata a todos los números como si fueran miembros, es uno de ellos. Otro al que hay que prestar atención son los mapeos inversos, que pueden hacer que el tipo de cosas como Object.keys(MyEnum) sea diferente de lo que normalmente podrías esperar.

Personalmente, recomiendo evitar los enums integrados de TypeScript debido a este tipo de rarezas. Es posible crear tus propios enums usando objetos simples de JavaScript con as const de TypeScript, y hacer que se comporten de manera casi exactamente igual. De hecho, en este ejemplo en particular pueden comportarse mejor, porque TypeScript solo considerará que los números específicos que has especificado son miembros de tu enum.

Hay tanto ventajas como desventajas en crear tus propios enums sin la palabra clave enum:

+ La sintaxis es más familiar para los desarrolladores de JavaScript que son nuevos en TypeScript

+ El JavaScript generado es más obvio, porque solo se eliminan las anotaciones de TypeScript

+ TypeScript no generará búsquedas inversas para los enums numéricos, lo cual puede ser poco intuitivo y causar problemas inesperados

+ TypeScript no tratará nada con el tipo number como si pudiera ser un miembro de un enum numérico

- TypeScript no generará el tipo asociado a un enum por ti, por lo que necesitas crearlo tú mismo, haciendo el código un poco más verboso

- Debido a que el tipo se construye como una unión de tipos constantes (por ejemplo, 'a' | 'b'), es posible que no obtengas una autocompletación tan útil en tu IDE porque sugerirá esos valores directamente en lugar de sugerir que los accedas a través de tu objeto enum

- Siempre necesitas especificar un valor para cada clave, mientras que para los enums numéricos de TypeScript puedes omitir los inicializadores.


Personalmente, utilizo un tipo de utilidad EnumTypeOf para ayudar con la desventaja de tener que construir un tipo manualmente. Aparte de esa desventaja, encuentro que los enums basados en objetos son más fáciles e intuitivos de usar.

type EnumTypeOf<T extends Record<string, unknown>> = T[keyof T];

const MixEnum = {
  HELLO: 'hello',
  WORLD: 2,
} as const;
type MixEnum = EnumTypeOf<typeof MixEnum>;

const ms1: MixEnum = String('foo'); // Type 'string' is not assignable to type 'MixEnum'.
const ms2: MixEnum = String('hello'); // Type 'string' is not assignable to type 'MixEnum'.

const mn1: MixEnum = Math.random(); // Type 'number' is not assignable to type 'MixEnum'.
const mn2: MixEnum = Number('99999'); // Type 'number' is not assignable to type 'MixEnum'.
const mn3: MixEnum = MixEnum.WORLD + 100; // Type 'number' is not assignable to type 'MixEnum'.

Área de juego de TypeScript

Artículos relacionados