TypeScript基础之typeof 类型操作符

前言 文中内容都是参考https://www.typescriptlang.org/docs/handbook/2/typeof-types.html , 以及参考
TypeScript 之 Typeof Type Operator --- mqyqingfeng 内容。
typeof 类型操作符 先来看看JavaScript中typeof的用法:
具体可参考 MDN typeof

typeof 操作符返回一个字符串,表示未经计算的操作数的类型。
类型 结果
Undefined "undefined"
Null "object"
Boolean "boolean"
Number "number"
BigInt(ECMAScript 2020 新增) "bigint"
String "string"
Symbol (ECMAScript 2015 新增) "symbol"
宿主对象(由 JS 环境提供) 取决于具体实现
Function 对象 "function"
其他任何对象 "object"
// Undefined typeof undefined === 'undefined'; // true typeof declaredButUndefinedVariable === 'undefined'; // truetypeof null === 'object'; // true

TypeScript中的typeof常见用途是在类型上下文中获取变量或者属性的类型, 此外还可以配合ReturnType获取函数的返回值类型, 以及配合 keyof 使用。
如:
1. 获取变量类型
function fn (x: string | number) { if (typeof x === 'string') { x.toFixed(2); // Property 'toFixed' does not exist on type 'string'. return x.split(''); } // ... }

2. 获取对象的类型
interface IPerson { name: string; age: number; } let person: IPerson = { name: 'xman', age: 18 }; type Person = typeof person; let p: Person = { name: 'zxx', age: 20 }

以上代码中通过typeof获取到person对象的类型,之后我们就可以使用Person类型。
对于嵌套对象也是一样:
const userInfo = { name: 'xman', age: 18, address: { provice: '湖北', city: '武汉' } }type UserInfo = typeof userInfo;

此时UserInfo类型如下:
type UserInfo = { name: string; age: number; address: { provice: string; city: string; }; }

对只读属性的数组:
let arr: readonly number[] = [1, 2, 3]; type Type = typeof arr; // type Type = readonly number[]let arr1: Type = [2, 100]; arr1.push(1); // type Type = readonly number[]

3. 获取函数的类型
function add (x: number, y: number): number { return x + y; } type Add = typeof add;

此时Add类型为
type Add = (x: number, y: number) => number

看下如果没有显式的描述函数返回类型,typeof会不会显示出返回类型:
function fn(x: string | number) { if (typeof x === "string") { return x.split(""); } return x; }type Fn = typeof fn;

此时Fn类型为:
type T = (x: string | number) => number | string[]

可以看出, 返回类型都推断出来了。
4. 对 enum 使用 typeof
enum 是一种新的数据类型,但在具体运行的时候,它会被编译成对象
enum Direction { Up = 1, Down, Left, Right, }

编译成JS后代码:
"use strict"; var Direction; (function (Direction) { Direction[(Direction["Up"] = 1)] = "Up"; Direction[(Direction["Down"] = 2)] = "Down"; Direction[(Direction["Left"] = 3)] = "Left"; Direction[(Direction["Right"] = 4)] = "Right"; })(Direction || (Direction = {}));

Direction值为:
{ 1: "Up", 2: "Down", 3: "Left", 4: "Right", Up: 1, Down: 2, Left: 3, Right: 4, };

对Direction使用typeof
type Result = typeof Direction; let res: Result = { Up: 2, Down: 4, Left: 6, Right: 8, };

此时Result类型类似于:
{ Up: number, Down: number, Left: number, Right: number, }

5. 对class 使用 typeof
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } }let PersonClass: typeof Person; // let PersonClass: new (name: string, age: number) => Personlet person = new PersonClass("xman", 18);

使用typeof Person,意思是取Person类的类型,而不是实例的类型。 或者更确切的说:获取Person标识符的类型,也就是构造函数的类型。 这个类型包含了类的所有静态成员和构造函数。 之后,我们在PersonClass上使用new,创建PersonClass的实例。
6. 配合ReturnType获取函数的返回值类型
ReturnType定义:
type ReturnType any> = T extends (...args: any) => infer R ? R : any;

infer在这里用于提取函数类型的返回值类型。ReturnType 只是将 infer R 从参数位置移动到返回值位置,因此此时 R 即是表示待推断的返回值类型。
使用:
type Predicate = (x: unknown) => boolean; type K = ReturnType
; // type K = boolean

如果我们直接对一个函数名使用 ReturnType ,我们会看到这样一个报错:
function f() { return { x: 10, y: 3 }; } type P = ReturnType; // 'f' refers to a value, but is being used as a type here.

这是因为值(values)和类型(types)并不是一种东西。为了获取值 f 也就是函数 f 的类型,我们就需要使用 typeof
function f() { return { x: 10, y: 3 }; } type P = ReturnType; // type P = { //x: number; //y: number; // };

7. 配合 keyof 使用
在 TypeScript 中,typeof 操作符可以用来获取一个变量或对象的类型。而 keyof 操作符可以用于获取某种类型的所有键,其返回类型是联合类型。
结合在一起使用:
const obj = { name: "xman", age: 18, }; let k1: keyof typeof obj; // let k1: "name" | "age"const obj = { 1: 'one', 2: 'two', 3: 'three' } type k1 = keyof typeof obj; // typeof obj 的结果为 { //1: string; //2: string; //3: string; // } // type k1 = 1 | 2 | 3enum Direction { Up = 1, Down, Left, Right, }type Result = keyof typeof Direction; // type Result = "Up" | "Down" | "Left" | "Right"

8. 对 const 断言字面量使用
let str1 = 'hello'; // let str1: stringtype T1 = typeof str; // type T1 = stringlet str2 = 'hello' as const; // let str2 = 'hello' as const; type T2 = typeof str2; // type T2 = "hello"

数组字面量应用 const 断言后,它将变成 readonly 元组,通过 typeof 操作符获取元组中元素值的联合类型
let arr1 = [1, 2, 3]; // let arr1: number[]type T1 = typeof arr1; // type T1 = number[]let arr2 = [1, 2, 3] as const; // let arr2: readonly [1, 2, 3]type T2 = typeof arr2; // type T2 = readonly [1, 2, 3]

对象字面量应用 const断言后, 对象字面量的属性,将使用 readonly 修饰
let obj1 = { name: "xman", age: 18 }; // let obj1: { //name: string; //age: number; // }; type T1 = typeof obj1; // type T1 = { //name: string; //age: number; // }; let obj2 = { name: "xman", age: 18 } as const; // let obj2: { //readonly name: "xman"; //readonly age: 18; // }; type T2 = typeof obj2; // type T2 = { //readonly name: "xman"; //readonly age: 18; // };

同样适用于包含引用类型的数组:
let arr1 = [ { name: "xman", age: 18 }, { name: "zxx", age: 22 }, ]; // let arr1: { //name: string; //age: number; // }[]; type T1 = typeof arr1; // type T1 = { //name: string; //age: number; // }[]; let arr2 = [ { name: "xman", age: 18 }, { name: "zxx", age: 22 }, ] as const; // let arr2: readonly [ //{ //readonly name: "xman"; //readonly age: 18; //}, //{ //readonly name: "zxx"; //readonly age: 22; //} // ]; type T2 = typeof arr2; // type T2 = readonly [ //{ //readonly name: "xman"; //readonly age: 18; //}, //{ //readonly name: "zxx"; //readonly age: 22; //} // ]; type T3 = typeof arr2[number]['name']; // type T3 = "xman" | "zxx"

以上ts代码均在 https://www.typescriptlang.or... 上运行过,版本为4.7.2。
最后, 如有错误,欢迎各位大佬指点!感谢!
参考资料 【TypeScript基础之typeof 类型操作符】https://www.typescriptlang.org/docs/handbook/2/typeof-types.html
https://github.com/mqyqingfeng/Blog/issues/224

    推荐阅读