Чтобы понять, как keyof typeof
используется в Typescript, сначала вам нужно понять, что такое буквальные типы и объединение буквальных типов. Итак, я сначала объясню эти концепции, а затем подробно объясню keyof
и typeof
по отдельности. После этого я вернусь к enum
, чтобы ответить на вопросы, заданные в вопросе. Это длинный ответ, но примеры легко понять.
Буквальные типы
Типы литералов в Typescript - это более конкретные типы string
, number
или boolean
. Например, "Hello World"
- это string
, но string
не "Hello World"
. "Hello World"
- это более конкретный тип типа string
, поэтому это буквальный тип.
Тип литерала можно объявить следующим образом:
type Greeting = "Hello"
Это означает, что объект типа Greeting
может иметь только string
значение "Hello"
и никакое другое значение string
или любое другое значение любого другого типа, как показано в следующем коде:
let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi" // Error: Type '"Hi"' is not assignable to type '"Hello"'
Литеральные типы сами по себе бесполезны, однако в сочетании с типами объединения, псевдонимами типов и защитой типов они становятся мощными.
Ниже приводится пример объединения буквальных типов:
type Greeting = "Hello" | "Hi" | "Welcome"
Теперь объект типа Greeting
может иметь значение "Hello"
, "Hi"
или "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
keyof
некоторого типа T
дает вам новый тип, который является объединением литеральных типов, и эти литеральные типы являются именами свойств T
. Результирующий тип - это подтип строки.
Например, рассмотрим следующий interface
:
interface Person {
name: string
age: number
location: string
}
Использование оператора keyof
для типа Person
даст вам новый тип, как показано в следующем коде:
type SomeNewType = keyof Person
Этот SomeNewType
представляет собой объединение литеральных типов ("name" | "age" | "location"
), состоящее из свойств типа Person
.
Теперь вы можете создавать объекты типа SomeNewType
:
let newTypeObject: SomeNewType
newTypeObject = "name" // OK
newTypeObject = "age" // OK
newTypeObject = "location" // OK
newTypeObject = "anyOtherValue" // Error...
keyof typeof
вместе на объекте
Как вы, возможно, уже знаете, оператор typeof
указывает тип объекта. В приведенном выше примере интерфейса Person
мы уже знали тип, поэтому нам просто нужно было использовать оператор keyof
для типа Person
.
Но что делать, если мы не знаем тип объекта или у нас просто есть значение, а не тип этого значения, как показано ниже?
const bmw = { name: "BMW", power: "1000hp" }
Здесь мы вместе используем keyof typeof
.
typeof bmw
дает вам тип: { name: string, power: string }
И затем оператор keyof
дает вам буквальное объединение типов, как показано в следующем коде:
type CarLiteralType = keyof typeof bmw
let carPropertyLiteral: CarLiteralType
carPropertyLiteral = "name" // OK
carPropertyLiteral = "power" // OK
carPropertyLiteral = "anyOther" // Error...
keyof typeof
on an enum
В Typescript перечисления используются как типы во время компиляции для обеспечения безопасности типов для констант, но они обрабатываются как объекты во время выполнения. Это связано с тем, что они преобразуются в простые объекты после компиляции кода Typescript в Javascript. Итак, объяснение вышеупомянутых объектов применимо и здесь. Пример, приведенный OP в вопросе:
enum ColorsEnum {
white = '#ffffff',
black = '#000000',
}
Здесь ColorsEnum
существует как объект во время выполнения, а не как тип. Итак, нам нужно вызвать операторы keyof typeof
вместе, как показано в следующем коде:
type Colors = keyof typeof ColorsEnum
let colorLiteral: Colors
colorLiteral = "white" // OK
colorLiteral = "black" // OK
colorLiteral = "red" // Error...
Вот и все! Надеюсь, это поможет.
person
Yogesh Umesh Vaity
schedule
06.07.2020