React中的这个TS骚操作秀到我了

更新日期: 2022-01-25 阅读: 1.4k 标签: React

前言

最近在写react时定义变量类型时,无意点到了ElementType,然后在node_modules/@types/react/index.d.ts 中发现了这段代码


牛啊,虽然我没太看懂,但是就是觉得挺牛的。

Google一下

但是后来咱一Google,发现网上管这个叫类型过滤,是一个实用的TS写法。
来看下面这个例子:

 interface Example{
     a:string;
     b:number;
     c:number;
     d:string;
     ...
     
 }

我们有一个Example的接口,但是咱们现在想对这个接口做一些处理,只希望留下类型为string的属性,这样咱们应该咋做?就可以使用咱们自己定义的FilterType。

type newExample = FilterType<Example,string> // {a:string;d:string;...}

咱们来看看FilterType是如何实现的:

    type FilterType<Source, Types> = Pick<
      Source, 
      {
        [K in keyof Source]: Source[K] extends Types ? K : never
      }[keyof Source]
    >;

分析

首先咱们先来看看代码中出现的几个utility types。(大佬直接跳过)

in

in 可以遍历枚举类型,类似 for...in

type Example = 'a' | 'b' | 'c' | 'd'
type Obj = {
  [T in Example]: string;  // 遍历Example,把每个key都赋值string类型
}
/* 等价于 
  type Obj = {
    a: string;
    b: string;
    c: string;
    d: string;
  }
*/

keyof

TS官方文档中把它称作索引类型查询操作符,其实就是取到类型的key,类似Object.keys() 虽然我不知道这样类比对不对。

interface Example {
    a: string;
    b: string;
    c: number;
    d: boolean;
}
    
type Keys = keyof Example   // 等价于 type Keys = 'a' | 'b' | 'c' | 'd'

条件判断

interface A {
    a:string;
}

interface B extends A {
    b:string;
} 

// B是否继承于A?若是,则为number类型;若不是,则为string类型
type C = B extends A ? number : string  // 等价于 type C = number

开始剖析

先看一个例子,揭开她的面纱,不,是口罩:

type Mask<source,types> = {
    [K in keyof source]:source[K] extends types ? K : never;
}
interface Example{
    name:string;
    height:number
}
type newType = Mask<Example,string> // { name:'name'; height:never}

这时候咱们看到一个{ name:'name'; height:never} ,what??? 这有啥用?

别急!接下来咱们继续看下面这个例子,揭开她的外套:
来看一个可以记在笔记本上的小知识点:索引访问接口属性

type person = { 
    name:"Angus";
    height:185;
}["name" | "height"]

等价于:

type person = "Angus" | 185

注意的是,当value为never时,就会访问不到

type person = { 
    name:"Angus";
    height:185;
    girlFriend:never;
}["name" | "height" | "girlFriend"]

等价于

type person = "Angus" | 185

(singleDog的自嘲

那知道了索引访问接口属性有啥用呢?来看下面这个例子,揭开她的clothes:

type Clothes<source,types> = {
    [K in keyof source]:source[K] extends types ? K : never;
}[keyof source]

interface Example{
    name:string;
    height:number;
    home:string
}
type newType = Clothes<Example,string> // type newType = "name | home"

这样我们就能拿到我们想要的类型的联合类型。
最后一步,咱们揭开***
hold on ,咱们先了解一下Pick。
Pick是在一个类型对象中,挑选几个类型,组成一个新的的类型。

interface Angus{
    name:string;
    height:number;
    wight:number;
}
type newAngus = Pick<Angus,'name' | 'height'> //{name:string;height:number}

它的实现:

type Pick<T,K extends keyof T> = {
   [P in K] : T[P];
}

然后我们来看Google上的那个例子:

type FilterType<Source, Types> = Pick<
      Source, 
      {
        [K in keyof Source]: Source[K] extends Types ? K : never
      }[keyof Source]
    >;

是不是茅厕顿开!!!通过Pick就可以挑选我们想要的属性了。

{
  [K in keyof Source]: Source[K] extends Types ? K : never
}[keyof Source]

这两行的代码就能拿到我们想要的属性。再通过Pick一下就完事。有没有被秀到?

拓展

那咱们再来看看TS中其他的一些工具类型吧

Omit

Omit(a,b) 接收两个参数,第一个是要编辑的基本类型,第二个是你要删除的类型。

type Person = {
    name:string;
    sex:string;
}
type newPerson = Omit<Person,'name'> // {sex:string}

看看它咋实现的:

type Omit <T,K extends keyof any> = Pick<T,Exclude<keyof T,K>>;

Partial

Partial 可以快速把某个接口类型中定义的属性变成可选的(Optional)

type Person = {
   name:string;
   sex:string;
}
type newPerson = Partial<Person> // {name?:string;sex?:string}

看看它咋实现的:

type Partial <T> = {
   [P in keyof T]?: T[P]
}

Exclude

用于删除类型集合中的指定类型.

type a = string | number
type newPerson = Exclude<a,string>  //number

实现:

type Exclude<T, U> = T extends U ? never : T

Readonly

将接口所有属性变为只读的.

type Person = {
    name:string;
    sex:string;
}
type newPerson = Readonly<Person> 
// type newPerson = {readonly name: string;readonly sex: string;}

实现:

type Readonly<T> = { readonly [P in keyof T]: T[P]; }

ReturnType

ReturnType的作用是用于获取函数 T 的返回类型。

    type T0 = ReturnType<() => string>; // string 
    type T1 = ReturnType<(s: string) => void>; // void
    type T2 = ReturnType<() => T>; // {} 
    type T3 = ReturnType<() => T>; // number[] 
    type T4 = ReturnType; // any 
    type T5 = ReturnType; // any 
    type T6 = ReturnType; // Error 
    type T7 = ReturnType; // Error

实现:

type ReturnType any> = T extends (...args: any) => infer R ? R : any;

Parameters

Parameters的作用是用于获取函数 T 的参数类型。

type getuserInfo = (user: string) => void
// Parameters<T>的作用是用于获取函数 T 的参数类型。
type ParametersUserInfo = Parameters<getuserInfo>
作者:Angus安格斯
链接:https://juejin.cn/post/7052949415350239246

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/11067

相关推荐

Gatsby.js_一款基于React.js静态站点生成工具

Gatsby能快速的使用 React 生态系统来生成静态网站,可以结合React Component、Markdown 和服务端渲染来完成静态网站生成让他更强大。

解决vscode 开发react 导入绝对路径 无法跳转的问题

相对路径可正常跳转,但是在webpack配置alias使用绝对路径后无法跳转.解决办法:需要添加一个jsconfig文件,如下:

react router中页面传值的三种方法

这篇文章主要介绍React Router定义路由之后如何传值,有关React和React Router 。react router中页面传值的三种方法:props.params、query、state

React常用hook的优化useEffect浅比较

先说说react原版的useEffect使用起来不便的地方,这里的effect每次更新都会执行,因为第三个参数一直是不等的,第二是在deps依赖很多的时候是真的麻烦

React 监听页面滚动,界面动态显示

当页面滚动时,如何动态切换布局/样式, 添加滚动事件的监听/注销

React + Webpack 构建打包优化

React 相关的优化:使用 babel-react-optimize 对 React 代码进行优化,检查没有使用的库,去除 import 引用,按需打包所用的类库,比如 lodash 、echarts 等.Webpack 构建打包存在的问题两个方面:构建速度慢,打包后的文件体积过大

react-router v4 按需加载的配置方法

在react项目开发中,当访问默认页面时会一次性请求所有的js资源,这会大大影响页面的加载速度和用户体验。所以添加按需加载功能是必要的,以下是配置按需加载的方法

React事件处理函数必须使用bind(this)的原因

学习React的过程中发现调用函数的时候必须使用bind(this),之后直接在class中声明函数即可正常使用,但是为什么呢,博主进行了一番查阅,总结如下。

grpc-web与react的集成

使用create-react-app脚手架生成react相关部分,脚手架内部会通过node自动起一个客户端,然后和普通的ajax请求一样,和远端服务器进行通信,只不过这里采用支持rpc通信的grpc-web来发起请求,远端采用docker容器的node服务器,node服务器端使用envoy作为代理

react中的refs属性的使用方法

React 支持一种非常特殊的属性 Ref ,你可以用来绑定到 render() 输出的任何组件上。这个特殊的属性允许你引用 render() 返回的相应的支撑实例( backing instance )。这样就可以确保在任何时间总是拿到正确的实例

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!