Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeScript 之 Typeof Type Operator #224

Open
mqyqingfeng opened this issue Nov 24, 2021 · 8 comments
Open

TypeScript 之 Typeof Type Operator #224

mqyqingfeng opened this issue Nov 24, 2021 · 8 comments

Comments

@mqyqingfeng
Copy link
Owner

mqyqingfeng commented Nov 24, 2021

前言

TypeScript 的官方文档早已更新,但我能找到的中文文档都还停留在比较老的版本。所以对其中新增以及修订较多的一些章节进行了翻译整理。

本篇整理自 TypeScript Handbook 中 「Typeof Type Operator」 章节。

本文并不严格按照原文翻译,对部分内容也做了解释补充。

typeof 类型操作符(The typeof type operator)

JavaScript 本身就有 typeof 操作符,你可以在表达式上下文中(expression context)使用:

// Prints "string"
console.log(typeof "Hello world");

而 TypeScript 添加的 typeof 方法可以在类型上下文(type context)中使用,用于获取一个变量或者属性的类型。

let s = "hello";
let n: typeof s;
// let n: string

如果仅仅用来判断基本的类型,自然是没什么太大用,和其他的类型操作符搭配使用才能发挥它的作用。

举个例子:比如搭配 TypeScript 内置的 ReturnType<T>。你传入一个函数类型,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'?

这是因为值(values)和类型(types)并不是一种东西。为了获取值 f 也就是函数 f 的类型,我们就需要使用 typeof

function f() {
  return { x: 10, y: 3 };
}
type P = ReturnType<typeof f>;
                    
// type P = {
//    x: number;
//    y: number;
// }

限制(Limitations)

TypeScript 有意的限制了可以使用 typeof 的表达式的种类。

在 TypeScript 中,只有对标识符(比如变量名)或者他们的属性使用 typeof 才是合法的。这可能会导致一些令人迷惑的问题:

// Meant to use = ReturnType<typeof msgbox>
let shouldContinue: typeof msgbox("Are you sure you want to continue?");
// ',' expected.

我们本意是想获取 msgbox("Are you sure you want to continue?") 的返回值的类型,所以直接使用了 typeof msgbox("Are you sure you want to continue?"),看似能正常执行,但实际并不会,这是因为 typeof 只能对标识符和属性使用。而正确的写法应该是:

ReturnType<typeof msgbox>

(注:原文到这里就结束了)

对对象使用 typeof

我们可以对一个对象使用 typeof

const person = { name: "kevin", age: "18" }
type Kevin = typeof person;

// type Kevin = {
// 		name: string;
// 		age: string;
// }

对函数使用 typeof

我们也可以对一个函数使用 typeof

function identity<Type>(arg: Type): Type {
  return arg;
}

type result = typeof identity;
// type result = <Type>(arg: Type) => Type

对 enum 使用 typeof

在 TypeScript 中,enum 是一种新的数据类型,但在具体运行的时候,它会被编译成对象。

enum UserResponse {
  No = 0,
  Yes = 1,
}

对应编译的 JavaScript 代码为:

var UserResponse;
(function (UserResponse) {
    UserResponse[UserResponse["No"] = 0] = "No";
    UserResponse[UserResponse["Yes"] = 1] = "Yes";
})(UserResponse || (UserResponse = {}));

如果我们打印一下 UserResponse

console.log(UserResponse);

// [LOG]: {
//   "0": "No",
//   "1": "Yes",
//   "No": 0,
//   "Yes": 1
// } 

而如果我们对 UserResponse 使用 typeof

type result = typeof UserResponse;

// ok
const a: result = {
      "No": 2,
      "Yes": 3
}

result 类型类似于:

// {
//	"No": number,
//  "YES": number
// }

不过对一个 enum 类型只使用 typeof 一般没什么用,通常还会搭配 keyof 操作符用于获取属性名的联合字符串:

type result = keyof typeof UserResponse;
// type result = "No" | "Yes"

TypeScript 系列

TypeScript 系列文章由官方文档翻译、重难点解析、实战技巧三个部分组成,涵盖入门、进阶、实战,旨在为你提供一个系统学习 TS 的教程,全系列预计 40 篇左右。点此浏览全系列文章,并建议顺便收藏站点。

微信:「mqyqingfeng」,加我进冴羽唯一的读者群。

如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。

@NameWjp
Copy link

NameWjp commented Dec 13, 2021

举个例子:比如搭配 TypeScript 内置的 ReturnTypep。你传入一个函数类型,ReturnTypep 会返回该函数的返回值的类型
=>
举个例子:比如搭配 TypeScript 内置的 ReturnType。你传入一个函数类型,ReturnType 会返回该函数的返回值的类型:

@zhijunw
Copy link

zhijunw commented Dec 30, 2021

写的好仔细 每天学习一篇

1 similar comment
@zhijunw
Copy link

zhijunw commented Dec 30, 2021

写的好仔细 每天学习一篇

@mqyqingfeng
Copy link
Owner Author

@NameWjp 感谢勘误,已更正~

@mqyqingfeng
Copy link
Owner Author

@zhijunw 感谢~ 主要是原文的文档写的好,哈哈

@consunmida
Copy link

大佬问下这个问题
enum UserResponse {
No = '0',
Yes = '1',
}
// 如果是数字枚举result 类型类似于:

// {
// "No": number,
// "YES": number
// }

// 如果是字符串枚举应该会是什么样呢?
let a = UserResponse.Yes
type result = typeof a;
let de: result = '1' // 为什么不能赋值?

@slogeor
Copy link

slogeor commented Jan 29, 2022

这个题目想考察哪个知识点

image

image

@lsc9
Copy link

lsc9 commented Apr 14, 2023

@mqyqingfeng // Ps:也是在严格模式下的
image
image
image

//  result的类型应该类似于:
{
    "No":  0,
    "YES":  1
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants