本文针对Typescript进行系统性讲解,但针对新人容易搞混的概念进行教学,尽量做到言简意赅,包教包会。
1.keyof 和 typeof 的用法常常搞不清
这里说一下keyof和typeof两个关键字的区别:
首先,我觉得在使用ts来开发的过程中,最重要的是在开发中引入了“类型定义和类型检查”这个概念,所以在使用各种关键字之前,一定要先区分这个变量是值还是类型。
那么什么是值,什么是变量呢?
-
值(Value) :
- 值是数据的一个具体表示。
- 值可以是任何数据类型,如数字、字符串、布尔值等。
- 值是静态的,意味着它们的值在程序的执行过程中不会改变。例如,字面量(如
5、"Hello"、true)都是值。
-
变量(Variable) :
- 变量是值的容器。
- 变量有一个类型,该类型定义了可以存储在变量中的值的范围。
- 变量的值可以在程序的执行过程中改变。
- 变量是通过变量名来标识的,例如
let x: number;这里x是一个变量,其类型是number。
那么,咱们再说说关键的keyof和typeof,
// 首先咱们定义一个类型
type commonOriginsType = {
name: String;
age: number;
}
// 其次咱们再定义一个值
// declare关键字用于声明来自第三方库或者全局变量、类型、函数而使用
declare const commonOrigins: commonOriginsType;
keyof 关键字:
keyof是一个类型操作符,它用于获取一个对象类型的所有键(属性名)组成的联合类型。- 它通常与对象字面量类型结合使用,来获取对象中所有键的类型。
type Keys = keyof commonOriginsType; // Keys 类型是 'String' | 'number'
- typeof 操作符:
typeof是一个值操作符,它返回一个表达式的类型。当与变量、函数、模块等结合使用时,它可以表示该表达式的类型。- 它常用于字面量类型和类类型。例如:
type TypeOfCommonOrigins = typeof commonOrigins;
// TypeOfCommonOrigins 类型其实就是我们声明的 { name: String; age: number; }
我在这里特别标明了他们是类型操作符和值操作符,是为什么呢?
看下面的例子:
type Keys = keyof commonOrigins;
假如你尝试这样的语句,你就会不出意外的commonOrigins' refers to a value, but is being used as a type here. Did you mean 'typeof commonOrigins'?(2749)得到这样一段报错。这是因为keyof是一个类型操作符,操作对象只能是类型,而你传入的commonOrigins是一个值,所以ts会说你试图将值当作一个类型来使用。
反之亦然,
type TypeOfCommonOrigins = typeof commonOriginsType;
这段代码你也会收获一个报错:'commonOriginsType' only refers to a type, but is being used as a value here.(2693),这是因为typeof本来是接受一个值的,但是你却将一个类型传给它,它当然运行不了了。
好,我们接下来再加深一下难度。
题目1: 请问下面这段代码会报错吗?
type a = keyof keyof { name: string; age: number; };
答案:不会,在 TypeScript 中,keyof 是一个类型操作符,它用于获取一个对象的所有键(属性名)组成的联合类型。keyof { name: string; age: number; }; 返回了一个联合类型,那么再继续用keyof 操作这个联合类型其实返回的是一样的,也就是说 keyof keyof { name: string; age: number; } 实际上与 keyof { name: string; age: number; } 是等价的,所以它虽然有点多余但它并不会报错。
题目2: 请问下面这段代码会报错吗?
// Record的定义是这样,它的范型接收两个参数,
type Record<K extends keyof any, T> = { [P in K]: T; };
type OriginType = Record<keyof typeof commonOrigins, string>
答案:不会,首先Record范型的第一个参数接收一个类型,而解读keyof typeof commonOrigins,我们需要从右往左进行解读。首先typeof是一个值操作符,它接收一个值,用户获取值的类型,typeof commonOrigins我们会得到类型{ name: string; age: number; },keyof是一个值操作符,接收一个值,所以 keyof { name: string; age: number; } 我们会得到联合类型 string | number。