Hola usuario de nuestra página, descubrimos la solución a tu interrogante, deslízate y la verás un poco más abajo.
Solución:
Para entender el keyof typeof
uso en TypeScript, primero debe comprender qué son tipos literales y unión de tipos literales. Entonces, explicaré estos conceptos primero y luego explicaré keyof
y typeof
individualmente en detalle. Después de eso, volveré a enum
para responder a lo que se pregunta en la pregunta. Es una respuesta larga, pero los ejemplos son fáciles de entender.
Tipos literales
Los tipos literales en Typecript son tipos más específicos de string
, number
o boolean
. Por ejemplo, "Hello World"
es un string
, pero un string
no es "Hello World"
. "Hello World"
es un tipo de tipo más específico string
, por lo que es un tipo literal.
Un tipo literal se puede declarar de la siguiente manera:
type Greeting = "Hello"
Esto significa que el objeto de tipo Greeting
puede tener solo un string
valor "Hello"
y ninguna otra string
value o cualquier otro valor de cualquier otro tipo como se muestra en el siguiente código:
let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi" // Error: Type '"Hi"' is not assignable to type '"Hello"'
Los tipos literales no son útiles por sí solos, sin embargo, cuando se combinan con tipos de unión, alias de tipos y guardias de tipos, se vuelven poderosos.
A continuación se muestra un ejemplo de unión de tipos literales:
type Greeting = "Hello" | "Hi" | "Welcome"
Ahora el objeto de tipo Greeting
puede tener el valor "Hello"
, "Hi"
o "Welcome"
.
let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi" // OK
greeting = "Welcome" // OK
greeting = "GoodEvening" // Error: Type '"GoodEvening"' is not assignable to type 'Greeting'
keyof
solamente
keyof
de algún tipo T
te da un nuevo tipo que es un unión de tipos literales y estos tipos literales son los nombres de las propiedades de T
. El tipo resultante es un subtipo de string.
Por ejemplo, considere lo siguiente interface
:
interface Person
name: string
age: number
location: string
Utilizando el keyof
operador en el tipo Person
le dará un nuevo tipo como se muestra en el siguiente código:
type SomeNewType = keyof Person
Esta SomeNewType
es una unión de tipos literales ("name" | "age" | "location"
) que se hace a partir de las propiedades del tipo Person
.
Ahora puedes crear objetos de tipo SomeNewType
:
let newTypeObject: SomeNewType
newTypeObject = "name" // OK
newTypeObject = "age" // OK
newTypeObject = "location" // OK
newTypeObject = "anyOtherValue" // Error...
keyof typeof
juntos en un objeto
Como ya sabrá, el typeof
operador le da el tipo de un objeto. En el ejemplo anterior de Person
interfaz, ya sabíamos el tipo, por lo que solo teníamos que usar la keyof
operador en tipo Person
.
Pero, ¿qué hacer cuando no sabemos el tipo de un objeto o simplemente tenemos un valor y no un tipo de ese valor como el siguiente?
const bmw = name: "BMW", power: "1000hp"
Aquí es donde usamos keyof typeof
juntos.
los typeof bmw
te da el tipo: name: string, power: string
Y luego keyof
El operador le da la unión de tipo literal como se muestra en el siguiente código:
type CarLiteralType = keyof typeof bmw
let carPropertyLiteral: CarLiteralType
carPropertyLiteral = "name" // OK
carPropertyLiteral = "power" // OK
carPropertyLiteral = "anyOther" // Error...
keyof typeof
en una enum
En TypeScript, las enumeraciones se utilizan como tipos en tiempo de compilación para lograr la seguridad de tipo para las constantes, pero se tratan como objetos en tiempo de ejecución. Esto se debe a que se convierten en objetos simples una vez que el código Typecript se compila en Javascript. Entonces, la explicación de los objetos anteriores también es aplicable aquí. El ejemplo dado por OP en la pregunta es:
enum ColorsEnum
white = '#ffffff',
black = '#000000',
Aquí ColorsEnum
existe como un objeto en tiempo de ejecución, no como un tipo. Entonces, necesitamos invocar keyof typeof
operadores juntos como se muestra en el siguiente código:
type Colors = keyof typeof ColorsEnum
let colorLiteral: Colors
colorLiteral = "white" // OK
colorLiteral = "black" // OK
colorLiteral = "red" // Error...
¡Eso es todo! Espero que ayude.
Un enum
crea una instancia object
. Con typeof
obtenemos el tipo generado automáticamente de esto enum
.
Ahora podemos obtener todos los índices con keyof
asegurarse Colors
solo puede contener uno de ellos.
Concepto erróneo común sobre TypeScript
TypeScript se describe a menudo como una capa de texto sobre el tiempo de ejecución de JavaScript. Como si tipos y valores vivieran en planos separados. Sin embargo, en TypeScript, algunas cosas son tipos y valores al mismo tiempo.
Este es true por:
- clases
- enumeraciones
- espacios de nombres.
Cuando puedes usar keyof
?
los keyof
La palabra clave solo funciona en el nivel de tipo. No puede aplicarlo a un valor de JavaScript.
Cuando necesitas keyof typeof
?
Cuando se trata de algo que es un tipo y un valor al mismo tiempo (como una clase o una enumeración), pero está interesado específicamente en cuál es el tipo de ese valor.
El ejemplo más simple:
const foo = bar: 42 ; // foo is a value
type Foo = typeof foo; // Foo is the type of foo
type KeyOfFoo = keyof Foo; // "keyof Foo" is the same as "keyof typeof foo", which is "bar"
En general, cuando vea esto:
type A = keyof typeof B;
los typeof B
parte le dice a TypeScript que mire el escribe de B. Puedes pensar en él como lanzando B a su tipo. Es como lanzar un objeto bidimensional a un espacio unidimensional.
Ya que typeof B
es un tipo, no un valor, ahora podemos usar keyof
en eso.
Ejemplo
Las clases son tipos y valores. Puede llamarlos, pero también puede usar keyof
en ellos.
declare class Foo
static staticProperty: string;
dynamicProperty: string;
type Constructor = typeof Foo;
type Instance = Foo;
type A = keyof Constructor; // "prototype" | "staticProperty"
type B = keyof Instance; // "dynamicProperty"
Mediante el uso typeof
Juntos con keyof
, podemos alternar entre usar keyof
en contra de ejemplo tipo y el constructor escribe.