Podemos restringir fácilmente el valor admitido utilizando tipos literales como los siguientes
type GenderConfig = { gender: 1 | 0 } const obj: GenderConfig = { gender: 100 // throw error because value is not 1 or 0 } Ahora, en la medida de lo posible, me gustaría evitar los números mágicos 1 y 0 .
así que traté de definir una enumeración para eso
enum Gender { MALE= 1, FEMALE=0, } type GenderConfig = { gender: Gender } const obj: GenderConfig = { gender: 100 // This doesn't throw error anymore? } Sorprendentemente, gender: 100 ya no arroja un error que no entiendo la razón detrás de esto.
Lo que ha creado aquí es una enumeración numérica . El JavaScript generado se ve así:
var Gender; (function (Gender) { Gender[Gender["MALE"] = 1] = "MALE"; Gender[Gender["FEMALE"] = 0] = "FEMALE"; })(Gender || (Gender = {}));En la consola, este objeto se ve así:
Object 0: "FEMALE" 1: "MALE" FEMALE: 0 MALE: 1Debajo del capó, la enumeración es realmente solo un objeto de JavaScript con propiedades. Tiene las propiedades con nombre que definió y se les asigna un número que representa la posición en la enumeración en la que existen (Siendo FEMALE 0, MALE siendo 1), pero el objeto también tiene claves numéricas con un valor de cadena que representa la constante con nombre.
Por lo tanto, puede pasar números a una función que espera una enumeración. La enumeración en sí es tanto un número como una constante definida.
Esto parece anular el aspecto de tipo seguro de TypeScript, ya que puede pasar un número arbitrario a una función que espera esta enumeración. Sin embargo, hay dos razones por las que esto es útil:
Con respecto al punto (1): si declara una enumeración sin valores numéricos, por ejemplo, esto:
enum Gender { MALE = "Male", FEMALE = "Female" }entonces ya no puedes hacer esto:
const gender: Gender = "Male";Tendrás que hacer un reparto explícito:
const gender = "Male" as Gender;const MALE = 1; const FEMALE = 0; type Gender = typeof MALE | typeof FEMALE; type GenderConfig = { gender: Gender } const obj: GenderConfig = { gender: 100 // This is now throwing error } En lugar de usar enums , lo cambié a type y al usar la combinación de const y typeof , puedo evitar el número mágico y mejorar la legibilidad y la consistencia, gracias a los demás por la explicación.
Ya no uso tanto las enumeraciones porque son un poco complicadas. Tal vez esto sea posible de alguna manera, pero puedes usar cadenas como esta en su lugar:
type Gender = 'female' | 'male'; type GenderConfig = { gender: Gender }Por supuesto, es posible que deba agregar algún mapeo si realmente necesita la representación numérica en algún momento.