TypeScript中的“ keyof typeof”是什么意思?

use*_*776 12 typescript

例:

向我解释keyof typeofTypeScript的含义

enum ColorsEnum {
    white = '#ffffff',
    black = '#000000',
}

type Colors = keyof typeof ColorsEnum;
Run Code Online (Sandbox Code Playgroud)

最后一行等效于:

type Colors = "white" | "black"
Run Code Online (Sandbox Code Playgroud)

但是它是如何工作的呢?

我希望typeof ColorsEnum返回类似的内容"Object",然后keyof "Object"不做任何有趣的事情。但是我显然是错的。

Yog*_*ity 230

要了解keyof typeofTypescript 中的用法,首先需要了解什么是字面量类型字面量类型的。所以,我会先解释这些概念,然后再详细解释keyoftypeof单独。之后,我会回来enum回答问题中提出的问题。这是一个很长的答案,但例子很容易理解。


文字类型

Typescript 中的文字类型是string,number或 的更具体类型boolean。例如,"Hello World"是 a string,但 astring不是"Hello World""Hello World"是更具体的 type 类型string,所以它是一个字面类型。

文字类型可以声明如下:

type Greeting = "Hello"
Run Code Online (Sandbox Code Playgroud)

这意味着 type 的对象Greeting只能有一个string"Hello"而不能有其他string值或任何其他类型的任何其他值,如以下代码所示:

let greeting: Greeting
greeting = "Hello" // OK
greeting = "Hi"    // Error: Type '"Hi"' is not assignable to type '"Hello"'
Run Code Online (Sandbox Code Playgroud)

文字类型本身没有用处,但是当与联合类型、类型别名和类型保护结合使用时,它们会变得强大。

以下是文字类型联合的示例:

type Greeting = "Hello" | "Hi" | "Welcome"
Run Code Online (Sandbox Code Playgroud)

现在 type 的对象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'
Run Code Online (Sandbox Code Playgroud)

keyof 只要

keyofof some typeT给你一个新类型,它是文字类型联合,这些文字类型是T. 结果类型是字符串的子类型。

例如,请考虑以下情况interface

interface Person {
    name: string
    age: number
    location: string
}
Run Code Online (Sandbox Code Playgroud)

keyof在类型上使用运算符Person将为您提供一个新类型,如以下代码所示:

type SomeNewType = keyof Person
Run Code Online (Sandbox Code Playgroud)

SomeNewType"name" | "age" | "location"由 type 的属性组成的文字 types( )的联合Person

现在您可以创建类型的对象SomeNewType

let newTypeObject: SomeNewType
newTypeObject = "name"           // OK
newTypeObject = "age"            // OK
newTypeObject = "location"       // OK
newTypeObject = "anyOtherValue"  // Error...
Run Code Online (Sandbox Code Playgroud)

keyof typeof 一起在一个物体上

您可能已经知道,typeof运算符为您提供对象的类型。在上面的Person接口示例中,我们已经知道类型,所以我们只需要keyof在 type 上使用运算符Person

但是,当我们不知道对象的类型或者我们只有一个值而不是该值的类型时该怎么办,如下所示?

const bmw = { name: "BMW", power: "1000hp" }
Run Code Online (Sandbox Code Playgroud)

这是我们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...
Run Code Online (Sandbox Code Playgroud)

keyof typeof 在一个 enum

在 Typescript 中,枚举在编译时用作类型以实现常量的类型安全,但它们在运行时被视为对象。这是因为,一旦将 Typescript 代码编译为 Javascript,它们就会转换为普通对象。因此,上述对象的解释也适用于此。OP在问题中给出的例子是:

enum ColorsEnum {
    white = '#ffffff',
    black = '#000000',
}
Run Code Online (Sandbox Code Playgroud)

这里ColorsEnum在运行时作为对象存在,而不是作为类型存在。所以,我们需要一起调用keyof typeof操作符,如下面的代码所示:

type Colors = keyof typeof ColorsEnum

let colorLiteral: Colors
colorLiteral = "white"  // OK
colorLiteral = "black"  // OK
colorLiteral = "red"    // Error...
Run Code Online (Sandbox Code Playgroud)

就是这样!希望有帮助。

  • 这是一个典型的 Stack Overflow 答案,应该用来向新用户解释如何回答问题。非常好,这应该是公认的答案。出色的。 (11认同)

Jam*_* EJ 37

keyof 接受一个对象类型并返回一个接受任何对象键的类型。

type Point = { x: number; y: number };
type P = keyof Point; // type '"x" || "y"'

const coordinate: P = 'z' // Type '"z"' is not assignable to type '"x" | "y"'.
Run Code Online (Sandbox Code Playgroud)

typeof 与 TypeScript 类型

typeof 在 javascript 对象上调用时的行为与在 typescript 类型上调用时的行为不同。

  • TypeScript在运行时调用 javascript 值时使用javascript 的 typeof并返回其中之一"undefined", "object", "boolean", "number", "bigint", "string", "symbol", "function"
  • TypeScript 的 typeof在类型值上调用,但也可以在类型表达式中调用 javascript 值。它还可以推断 javascript 对象的类型,返回更详细的对象类型。
type Language = 'EN' | 'ES'; 
const userLanguage: Language = 'EN';
const preferences = { language: userLanguage, theme: 'light' };

console.log(typeof preferences); // "object"
type Preferences = typeof preferences; // type '{language: 'EN''; theme: string; }'
Run Code Online (Sandbox Code Playgroud)

因为第二个typeof preferences是在类型表达式中,所以它实际上是 TypeScript 自己的typeof被调用的,而不是 javascript 的。

键类型

因为keyof是一个 TypeScript 概念,我们将调用 TypeScript 的typeof.

keyof typeof将推断 javascript 对象的类型并返回其键的联合类型。因为它可以推断出键的确切值,所以它可以返回它们文字类型的联合,而不是仅仅返回“字符串”。

type PreferenceKeys = keyof typeof preferences; // type '"language" | "theme"'
Run Code Online (Sandbox Code Playgroud)


Kar*_*ski 15

关于 TypeScript 的常见误解

TypeScript 通常被描述为 JavaScript 运行时之上的类型层。好像类型和值存在于不同的平面上。但是,在 TypeScript 中,有些东西同时是类型值。

这适用于:

  • 班级,
  • 枚举,
  • 命名空间。

什么时候可以用keyof

keyof关键字仅适用于类型级别。您不能将其应用于 JavaScript 值。

keyof typeof什么时候需要?

当您同时处理既是类型又是值的事物时(例如类或枚举),但您对值的类型特别感兴趣。

最简单的例子:

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"
Run Code Online (Sandbox Code Playgroud)

一般来说,当你看到这个时:

type A = keyof typeof B;
Run Code Online (Sandbox Code Playgroud)

typeof B部分告诉 TypeScript 查看B的类型。您可以将其视为将 B 转换为其类型。有点像将二维对象投射到一维空间。

由于typeof B是一个类型,而不是一个值,我们现在可以使用keyof它。

例子

类是类型和值。您可以调用它们,但也可以keyof对它们使用。

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"
Run Code Online (Sandbox Code Playgroud)

通过使用typeof与一起keyof,我们可以使用之间切换keyof实例类型和构造类型。


Mar*_*her 9

一个enum创建一个实例化object。随着typeof我们得到this的自动生成的类型enum

现在,我们可以获得所有索引,keyof以确保Colors只能包含其中一个索引。