这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

前期准备

本篇文章的编写目的是为了提升TS类型的书写质量,高质量的类型可以提高项目的可维护性并避免一些潜在的漏洞;

在学习本篇之前需要有一定的TS基础知识,在此基础上可以更好的完成各种类型的挑战,编写出属于自己的类型工具;

这里推荐我之前梳理的基础知识点 一份够用的TS常用特性总结TS中文文档 ;

目前只完成了easy类型和部分medium类型的训练,后续会持续补充;

easy

readonly

实现Readonly,接收一个泛型参数,并返回一个完全一样的类型,只是所有属性都会被readonly所修饰。

type MyReadonly<T> = {
readonly [P in keyof T] : T[P]
} interface Todo {
title: string;
description: string;
} const todoObj: MyReadonly<Todo> = {
title: "Hey",
description: "foobar",
}; console.log(todoObj.title)
todoObj.description = "barFoo"; // Error: cannot reassign a readonly property

first-of-array

实现First,他接受一个数组 T 并返回它的第一个元素类型

type First<T extends any[]> = T extends [] ? never : T[0];

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1] type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3

tuple-to-object

实现TupleToObject,传入元组类型,将元组类型转换为对象类型,这个对象类型的键/值都是从元组中遍历出来。

type TupleToObject<T extends readonly any[]> = {
[P in T[number]]: P;
}; const tuple = ["tesla", "model 3", "model X", "model Y"] as const; type result = TupleToObject<typeof tuple>; // expected { tesla: 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}

length of tuple

创建一个通用的Length,接受一个readonly的数组,返回这个数组的长度。

type Length<T extends readonly unknown[]> = T["length"];

type tesla = ["tesla", "model 3", "model X", "model Y"];
type spaceX = [
"FALCON 9",
"FALCON HEAVY",
"DRAGON",
"STARSHIP",
"HUMAN SPACEFLIGHT"
]; type teslaLength = Length<tesla>; // expected 4
type spaceXLength = Length<spaceX>; // expected 5

Exclude

从联合类型T中排除U的类型成员,来构造一个新的类型。

type MyExclude<T, U> = T extends U ? never : T;

type Result = MyExclude<"a" | "b" | "c", "a">; // 'b' | 'c'

Awaited

假如我们有一个 Promise 对象,这个 Promise 对象会返回一个类型。在 TS 中,我们用 Promise 中的 T 来描述这个 Promise 返回的类型。请你实现一个类型,可以获取这个类型。 例如:Promise,请你返回 ExampleType 类型。

type MyAwaited<T> = T extends PromiseLike<infer R> ? MyAwaited<R> : T

type ExampleType = Promise<string>

type Results = MyAwaited<ExampleType> // string

IF

实现一个 IF 类型,它接收一个条件类型 C ,一个判断为真时的返回类型 T ,以及一个判断为假时的返回类型 F。 C 只能是 true 或者 false, T 和 F 可以是任意类型。

type If<C extends boolean, T, F> = C extends true ? T : F;

type A = If<true, "a", "b">; // expected to be 'a'
type B = If<false, "a", "b">; // expected to be 'b'

Concat

在类型系统里实现 JavaScript 内置的 Array.concat 方法,这个类型接受两个参数,返回的新数组类型应该按照输入参数从左到右的顺序合并为一个新的数组。

type Concat<T extends any[], U extends any[]> = [...T, ...U];

type ResultConcat = Concat<[1], [2]>; // expected to be [1, 2]

Include

实现 Array.includes 方法,这个类型接受两个参数,返回的类型要么是 true 要么是 false。

type Includes<T extends readonly any[], U> =  U extends T[number] ? true : false

type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Esidisi'> // expected to be `false`

Push

实现通用的Array.push类型。

type Push<T extends readonly unknown[], U> = [...T, U];

type Resulted = Push<[1, 2], "3">; // [1, 2, '3']

Unshift

实现类型 Array.unshift类型。

type Unshift<T extends readonly unknown[], U> = [U, ...T];

type UnshiftList = Unshift<[1, 2], 0>; // [0, 1, 2,]

Parameters

实现内置的 Parameters 类型。

type MyParameters<T extends (...args: any[]) => any> = T extends (
...args: infer U
) => any
? U
: never; const foo = (arg1: string, arg2: number): void => {}; type FunctionParamsType = MyParameters<typeof foo>; // [arg1: string, arg2: number]

edium

ReturnType

不使用 ReturnType 实现 TypeScript 的 ReturnType 泛型。

type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

const fn = (v: boolean) => {
if (v) return 1;
else return 2;
}; type a = MyReturnType<typeof fn>; // 应推导出 "1 | 2"

Omit

不使用 Omit 实现 TypeScript 的 Omit<T, K> 泛型。Omit 会创建一个省略 K 中字段的 T 对象。

type MyOmit<T, K extends keyof any> = {
[key in Exclude<keyof T, K>]: T[key];
}; interface Todo {
title: string;
description: string;
completed: boolean;
} type TodoPreview = MyOmit<Todo, "description" | "title">; const todo: TodoPreview = {
completed: false,
};

ReadOnly2

实现一个通用MyReadonly2<T, K>,它带有两种类型的参数T和K。 K指定应设置为Readonly的T的属性集。如果未提供K,则应使所有属性都变为只读,就像普通的Readonly一样。

type MyReadonly2<T, K extends keyof T = keyof T> = {
readonly [P in K]: T[P];
} & {
[P in Exclude<keyof T, K>]: T[P];
}; interface Todo {
title: string;
description: string;
completed: boolean;
} const todos: MyReadonly2<Todo, "title" | "description"> = {
title: "Hey",
description: "foobar",
completed: false,
}; todos.title = "Hello"; // Error: cannot reassign a readonly property
todos.description = "barFoo"; // Error: cannot reassign a readonly property
todos.completed = true; // OK

DeepReadonly

实现一个通用的DeepReadonly,它将对象的每个参数及其子对象递归地设为只读。

type DeepReadonly<T> = T extends Function
? T
: {
readonly [K in keyof T]: K extends Object ? DeepReadonly<T[K]> : T[K];
}; type X = {
x: {
a: 1;
b: "hi";
};
y: "hey";
}; type Expected = {
readonly x: {
readonly a: 1;
readonly b: "hi";
};
readonly y: "hey";
}; type Todo = DeepReadonly<X>; // should be same as `Expected`

TupleToUnion

实现泛型TupleToUnion,它返回元组所有值的合集。

type TupleToUnion<T extends unknown[]> = T[number]

type Arr = ['1', '2', '3']

type Test = TupleToUnion<Arr> // expected to be '1' | '2' | '3'

LastOfArray

实现一个Last,它接受一个数组T并返回其最后一个元素的类型。

type Last<T extends unknown[]> = T extends [...unknown[], infer R] ? R : never

type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1] type tail1 = Last<arr1> // expected to be 'c'
type tail2 = Last<arr2> // expected to be 1

本文转载于:

https://juejin.cn/post/7193917621069152311

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--TS类型写不好?一起来训练提升吧!的更多相关文章

  1. 发布TS类型文件到npm

    最近发布了@types/node-observer包到npm,这里记录下发布过程 TS类型文件的包名通常以@types开头,使用npm publish发布以@types开头的包时需要使用付费账号.   ...

  2. 使用 yapi-to-typescript 生成接口响应数据的 TS 类型声明

    TS 是越写越爽,但是很不爽的是接口响应数据一堆,每次要去手写很麻烦. 最近正好后端接口文档从一个垃圾工具切换到了 Yapi,然后去搜了下可以通过接口文档自动生成 TS 类型声明,就自己搞了下,还是很 ...

  3. 如何理解 TS 类型编程中的 extends 和 infer

    extends extends 在TS类型编程中用法(T extends U),表示 T 中的某些在 U 里面,比较难描述,用法如下: T extends U ? X : Y 分为两种情况理解更直观一 ...

  4. opencv 手写选择题阅卷 (三)训练分类器

    opencv 手写选择题阅卷 (三)训练分类器 1,分类器选择:SVM 本来一开始用的KNN分类器,但这个分类器目前没有实现保存训练数据的功能,所以选择了SVN分类器; 2,样本图像的预处理和特征提取 ...

  5. Go+gRPC-Gateway(V2) 微服务实战,小程序登录鉴权服务(四):客户端强类型约束,自动生成 API TS 类型定义

    系列 云原生 API 网关,gRPC-Gateway V2 初探 Go + gRPC-Gateway(V2) 构建微服务实战系列,小程序登录鉴权服务:第一篇 Go + gRPC-Gateway(V2) ...

  6. 从零开始写一个武侠冒险游戏-6-用GPU提升性能(1)

    从零开始写一个武侠冒险游戏-6-用GPU提升性能(1) ----把帧动画的实现放在GPU上 作者:FreeBlues 修订记录 2016.06.19 初稿完成. 2016.08.05 增加对 XCod ...

  7. 从零开始写一个武侠冒险游戏-8-用GPU提升性能(3)

    从零开始写一个武侠冒险游戏-8-用GPU提升性能(3) ----解决因绘制雷达图导致的帧速下降问题 作者:FreeBlues 修订记录 2016.06.23 初稿完成. 2016.08.07 增加对 ...

  8. 从零开始写一个武侠冒险游戏-7-用GPU提升性能(2)

    从零开始写一个武侠冒险游戏-7-用GPU提升性能(2) ----把地图处理放在GPU上 作者:FreeBlues 修订记录 2016.06.21 初稿完成. 2016.08.06 增加对 XCode ...

  9. 程序员的恶性循环:加班->没空学习->老是写同等水平代码->无法提升代码质量->老是出BUG->老是需要修改->加班->...

    程序员的恶性循环:加班->没空学习->老是写同等水平代码->无法提升代码质量->老是出BUG->老是需要修改->加班->...

  10. 恕我直言,在座的各位根本写不好Java!

    其实,本不想把标题写的那么恐怖,只是发现很多人干了几年 Java 以后,都自认为是一个不错的 Java 程序员了,可以拿着上万的工资都处宣扬自己了,写这篇文章的目的并不是嘲讽和我一样做 Java 的同 ...

随机推荐

  1. 【XInput】游戏手柄模拟鼠标动作

    老周一般很少玩游戏,在某宝上买了一堆散件,计划在过年期间自己做个机械臂耍耍.头脑中划过一道紫蓝色的闪电,想起用游戏手柄来控制机械臂.机械臂是由树莓派(大草莓)负责控制,然后客户端通过 Socket U ...

  2. uniapp实现点击加载更多

    使用场景 举个栗子:外卖app当订单商品数量比较多时,不方便一次性展示出来.通常会展示一部分,并在页面给出一个查看更多功能.点击后即可自定义展示剩余内容,比如可以每次点击多展示N个内容,或展示所有. ...

  3. springboot+vue+elementui实现文件上传下载删除DEMO

    说明 前面搜索了几个关于springboot+vue+elementui上传下载的文章,感觉写的都不尽如人意.要么是功能不完善,不好用.再者就是源码提供的实在差劲,都不完整.一气之下,自己搞了一个实用 ...

  4. centos7安装postgresql9.6

    1.安装yum源 yum install -y https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg- ...

  5. Spring Boot图书管理系统项目实战-1.系统功能和架构介绍

    导航: next:2.项目搭建 1.项目源码 需要源码的朋友,请捐赠任意金额后留下邮箱发送:) 2.项目背景 自己闲着没事写的,供初学spring boot和在校大学生毕业设计学习交流.大神请忽略:) ...

  6. Java使用正则表达式判断字符串中是否包含某子字符串

    需求: 给定一个字符串s,判断当s中包含"tree fiddy"或"3.50"或"three thirty"子字符串返回true,否则返回f ...

  7. Java序列化(Serializable)与反序列化详解

    什么是序列化? Java序列化是在JDK 1.1中引入的,是Java内核的重要特性之一. Java序列化API允许我们将一个对象转换为流,并通过网络发送,或将其存入文件或数据库以便未来使用, 反序列化 ...

  8. RCE代码执行漏和命令执行漏洞

    前置知识: 漏洞检测: 在了解漏洞概念前,应该先知道一下这个漏洞如何检测的,我们应该或多或少听过白盒测试(白盒),黑盒测试(黑盒). 白盒测试: 白盒测试是对源代码和内部结构的测试,测试人员是可以知道 ...

  9. SpringCloud SpringBoot 组件使用:使用Nacos作为服务的注册中心和配置中心

    基础篇 一.什么是Nacos? 官方介绍是这样的: Nacos 致力于帮助您发现.配置和管理微服务.Nacos 提供了一组简单易用的特性集,帮助您实现动态服务发现.服务配置管理.服务及流量管理. Na ...

  10. Retrofit 的基本用法

    一.添加依赖和网络权限 添加依赖 implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup ...