本章节官方文档地址:Keyof Type Operator、Typeof Type Operator
keyof
类型操作符keyof
类型操作符接受一个对象类型作为参数,并基于它的键产生一个由字符串字面量或者数值字面量组成的联合类型。下面的类型 P
等同于类型 "x" | "y"
:
type Point = { x: number; y: number };
type P = keyof Point;
^
// type P = keyof Point
如果 keyof
操作的类型有 string
或者 number
类型的索引签名,那么 keyof
会返回该索引签名的类型:
type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish;
^
// type A = number
type Mapish = { [k: string]: boolean };
type M = keyof Mapish;
^
// type M = string | number
注意,在这个例子中,M
表示的类型是 string | number
—— 这是因为 JavaScript 对象的键总是会被强制转化为一个字符串,因此 obj[0]
等同于 obj["0"]
。
keyof
类型和映射类型结合的时候会发挥很大的作用,后续的章节我们也会进行介绍。
typeof
类型操作符JavaScript 中本身就有一个可用于表达式上下文的 typeof
操作符:
// 打印 "string"
console.log(typeof "Hello world");
TypeScript 则添加了一个可用于类型上下文的 typeof
操作符,让你可以引用某个变量或者属性的类型:
let s = "hello";
let n: typeof s;
^
// let n: string
像上面这样用于基本类型,作用并不是很大,但如果把 typeof
和其它类型操作符结合使用,就可以方便地表示多种模式了。举个例子,我们先来看一下预定义类型 ReturnType<T>
。它可以接受一个函数类型并将它的返回值类型返回出去:
type Predicate = (x: unknown) => boolean;
type K = ReturnType<Predicate>;
^
// type K = boolean
如果直接把函数名作为参数传递给 ReturnType
,那么我们会看到一个指示性错误:
function f() {
return { x: 10, y: 3 };
}
type P = ReturnType<f>;
^
// 'f' refers to a value, but is being used as a type here. Did you mean 'typeof f'?
记住,值和类型是不一样的,这里应该传入类型而不是值,因此我们可以改用 typeof
去引用值 f
的类型:
function f(){
return {
x: 10,
y: 3
};
}
type P = ReturnType<typeof f>;
^
/* type P = {
x: number;
y: number;
} */
TypeScript 有意限制 typeof
可以操作的表达式类型。具体地说,tyepof
只能作用于标识符(比如变量名)或者它们的属性。这可以避免让开发者编写他们认为可以执行的但实际上不能执行的代码:
// 这里应该改用 = ReturnType<typeof msgbox>
let shouldContinue: typeof msgbox("Are you sure you want to continue?");
^
// ',' expected.