原文链接: 为ramda添加类型

上一篇: 在线 ocr 文字识别 和 图片色值选取

下一篇: opencv opencv4nodejs 安装和简单抠图

原文做了更多, 受限于自己水平不够...

https://medium.com/free-code-camp/typescript-curry-ramda-types-f747e99744ab

https://github.com/millsp/ts-toolbelt

ramda目前的实现是使用重载, 比如简单的add函数, 有两个重载

对于pipe这种类型, 暴力使用枚举写法一点都不够优雅, 并且还限制了参数个数

01 提取函数参数

const fn01 = (name: string, age: number, single: false) => true;type Params<F extends (...args: any[]) => any> = F extends (...args: infer A
) => any? A: never;type argsFn01 = Params<typeof fn01>;
// type argsFn01 = [name: string, age: number, single: false]

02 取第一个和取剩下的

head表示第一个, tail表示去除第一个后剩下的, 和ramda中的略有区别

type Head<T extends any[]> = T extends [any, ...any[]] ? T[0] : never;
type h1 = Head<[string, number, boolean]>;
// type h1 = string
type h2 = Head<[]>;
// type h2 = nevertype Tail<T extends any[]> = ((...t: T) => any) extends (_: any,...tail: infer P
) => any? P: [];type t1 = Tail<[number, string, boolean]>;
// type t1 = [string, boolean]
type t2 = Tail<[boolean]>;
// type t2 = []
type t3 = Tail<[]>;
// type t3 = []

03 是否有剩余参数

type hasTail<T extends any[]> = T extends [] | [any] ? false : true;type t4 = hasTail<[]>;
// type t4 = falsetype t5 = hasTail<[string]>;
// type t5 = falsetype t6 = hasTail<[string, number]>;
// type t6 = true

04 infer的几种用法

推断对象属性

type ObjectInfer<T> = T extends { K: infer P } ? P : never;const obj1 = { K: "ace" };
const obj2 = { K: 1 };type t1 = ObjectInfer<typeof obj1>;
// type t1 = stringtype t2 = ObjectInfer<typeof obj2>;
// type t2 = numbertype t3 = ObjectInfer<string>;
// type t3 = never

推断函数参数和返回值

type FunctionInfer<T> = T extends (...args: infer A) => infer R? [A, R]: never;const f05 = (name: string, age: number) => true;
type t5 = FunctionInfer<typeof f05>;
// type t5 = [[name: string, age: number], boolean]

推断promise

type PromiseInfer<T> = T extends Promise<infer P> ? P : never;
const p = new Promise<string>((resolve) => resolve("abc"));
type t06 = PromiseInfer<typeof p>
// type t06 = string

推断数组

// 一样的效果
// type ArrayInfer<T> = T extends Array<infer P> ? P : never;
type ArrayInfer<T> = T extends (infer P)[] ? P : never;
const a1 = [1, "a", true];
type t07 = ArrayInfer<typeof a1>;
// type t07 = string | number | boolean

推断元组

// type TupleInfer<T> = T extends [infer P, ...(infer Q)[]] ? [P, Q] : never;
type TupleInfer<T> = T extends [infer P, ...Array<infer Q>] ? [P, Q] : never;
type t08 = TupleInfer<[string, number, boolean]>;
// type t08 = [string, number | boolean]

05 单参数 版

type CurryV0<P extends any[], R> = (args: Head<P>
) => HasTail<P> extends true ? CurryV0<Tail<P>, R> : R;declare function curryV0<P extends any[], R>(f: (...args: P) => R
): CurryV0<P, R>;const f1 = (name: string, age: number, single: boolean) => true;
const curry1 = curryV0(f1);
const r1 = curry1("")(1)(true);
// const r1: booleancurry1("")("");

06 多参数版, 但是推断有问题

使用可选参数, 但是与函数的参数消费不一致了, 所以返回值推断失效

type CurryV1<P extends any[], R> = (arg0: Head<P>,...rest: Tail<Partial<P>>
) => HasTail<P> extends true ? CurryV1<Tail<P>, R> : R;declare function CurryV1<P extends any[], R>(f: (...args: P) => R
): CurryV1<P, R>;const f1 = (name: string, age: number, single: boolean) => true;
const curry1 = CurryV1(f1);
const r1 = curry1("")(1)(true);
// const r1: booleanconst r2 = curry1("", 1, true);
// const r2: CurryV1<[age: number, single: boolean], boolean>

07 其他的类型推断

取最后一个

type Last<T extends any[]> = {0: Last<Tail<T>>;1: Head<T>;
}[HasTail<T> extends true ? 0 : 1];type t08 = Last<[string, number, boolean]>;
// type t08 = boolean
type t09 = Last<[]>;
// type t09 = never

元组或数组的长度

type Length<T extends any[]> = T["length"];
type t11 = Length<[]>;
// type t11 = 0type t12 = Length<[number, string]>;
// type t12 = 2// 如果使用变量会导致a04是数组, 这样长度就是会变化的,ts会返回nubmber
// const a04 = [1, "a", true];
type t13 = Length<[1, "a", true]>;
// type t13 = 3

在数组头部添加元素


type Prepend<V, T extends any[]> = ((head: V, ...args: T) => any) extends (...args: infer U
) => any? U: T;type t14 = Prepend<1, ["a", "b"]>;
// type t14 = [1, "a", "b"]type t15 = Prepend<number, [string, "a", "b", 2]>;
// type t15 = [number, string, "a", "b", 2]

去除列表中的前几项

使用递归, 每次向I中添加any, 并去除第一个元素, 当I的长度和N相等时, T已经去除了前N个了

type Drop<N extends Number, T extends any[], I extends any[] = []> = {0: Drop<N, Tail<T>, Prepend<any, I>>;1: T;
}[Length<I> extends N ? 1 : 0];
type t18 = Drop<2, [number, string, boolean, number]>;
// type t18 = [boolean, number]
type t19 = Drop<0, []>;
// type t19 = []
type t20 = Drop<3, [string]>;
// type t20 = []

转换函数

如果X继承Y, 则是X, 否则是Y

type Cast<X, Y> = X extends Y ? X : Y;type t21 = Cast<string, any>;
// type t21 = string
type t22 = Cast<[string], any>;
// type t22 = [string];
type t23 = Cast<[number], string>;
// type t23 = string

08

type CurryV3<P extends any[], R> = <T extends any[]>(...args: T
) => Length<Drop<Length<T>, P>> extends 0 ? R : CurryV3<Drop<Length<T>, P>, R>;

由于Drop的返回有两个, 所以报错了, 但是我们知道, Drop由于递归的原因只可能返回一个类型, 此时需要一个类型转换函数

使用类型转换函数后只剩下一个可能无限循环的警告

type CastDrop<N extends Number, T extends any[]> = Cast<Drop<N, T>, any[]>;type CurryV4<P extends any[], R> = <T extends any[]>(...args: T
) => Length<CastDrop<Length<T>, P>> extends 0? R: CurryV4<CastDrop<Length<T>, P>, R>;

有了准确的提示

type CastDrop<N extends Number, T extends any[]> = Cast<Drop<N, T>, any[]>;type CurryV4<P extends any[], R> = <T extends any[]>(...args: T
) => Length<CastDrop<Length<T>, P>> extends 0? R: CurryV4<CastDrop<Length<T>, P>, R>;declare function CurryV4<P extends any[], R>(f: (...args: P) => R
): CurryV4<P, R>;const f1 = (name: string, age: number, single: boolean) => true;
const curry1 = CurryV4(f1);
const r1 = curry1("")(1)(true);
// const r1: booleanconst r2 = curry1("", 1, true);
// const r2: boolean
const r3 = curry1("", 1)(true);
// const r3: boolean

为ramda添加类型相关推荐

  1. 问题.NET--win7 IIS唯一密钥属性“VALUE”设置为“DEFAULT.ASPX”时,无法添加类型为“add”的重复集合...

    问题现象:.NET--win7 IIS唯一密钥属性"VALUE"设置为"DEFAULT.ASPX"时,无法添加类型为"add"的重复集合 问 ...

  2. 在唯一密钥属性“name”设置为“Application”时,无法添加类型为“add”的重复集合项...

    配置一个网站后,出现[在唯一密钥属性"name"设置为"Application"时,无法添加类型为"add"的重复集合项]这个错误,记得之前 ...

  3. 无法添加类型为“mimeMap”的重复集合项

    无法添加类型为"mimeMap"的重复集合项 文章目录 无法添加类型为"mimeMap"的重复集合项 1.问题描述 2.问题原因 3.问题解决 1.问题描述 在 ...

  4. Python 添加类型标注 | 散发着自由松散气息的代码

    Python 添加类型标注 | 散发着自由松散气息的代码 Python 如此简洁,书写者在声明变量时甚至无需考虑类型. 但是简洁与复杂间,是存在一个平衡点的.当我们书写较为复杂的项目时,还是希望可以拥 ...

  5. (十九)美萍酒店管理系统:系统维护_系统设置_房间设置_添加类型、修改类型

    房间设置数据要求: 1.结账后状态部分: (1)"结账后()分钟后变为可供状态"文本框: 0--2500分钟,不能为空,整数 2.增加房间类型窗口 (1)"房间类型&qu ...

  6. 给个人博客的文件添加类型标签

    个人需求说明: 之前搭建的个人博客主页,为了更好的进行分类管理,我决定对每一篇添加分类标签,就像CSDN博客上的文章一样,如图: 标签:git ,就是我们这次要做的事情. 后端数据库设计: 为了保证后 ...

  7. IIS错误:在唯一密钥属性“fileExtension”设置为“.mp4”时,无法添加类型为“mimeMap”的重复集合项

    今天移服务器,之前项目部署在server2008上,config中的mime设置如下,运行正常: <staticContent><mimeMap fileExtension=&quo ...

  8. 在线 ocr 文字识别 和 图片色值选取

    原文链接: 在线 ocr 文字识别 和 图片色值选取 上一篇: js 颜色库 chroma 和 color 下一篇: 为ramda添加类型 图片颜色选取 https://tool.ahaoboy.co ...

  9. 全面理解Python中的类型提示(Type Hints)

    众所周知,Python 是动态类型语言,运行时不需要指定变量类型.这一点是不会改变的,但是2015年9月创始人 Guido van Rossum 在 Python 3.5 引入了一个类型系统,允许开发 ...

  10. 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门)

    by Preethi Kasireddy 通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门) (Why use stati ...

最新文章

  1. 独家 | ​多项式回归:从零开始学习梯度下降
  2. 72小时BCH日本生存挑战赛顺利完成
  3. python3练习,python3练习题 - 来自菜鸟的独白
  4. 智能手环功能模块设计_基于STM32实现智能手环设计
  5. Pwn环境配置(一)——安装虚拟机
  6. 系统:Centos 7.2 内核3.10.0-327.el7.x86_64 # 内核需要高于2.6.32
  7. python多个main方法_Python,main方法未运行(同一文件中有多个类)
  8. C++总结:static_cast ,reinterpret_cast
  9. jq为a标签绑定的onclick事件在移动端不响应
  10. # 淘宝客导购小程序最新版本
  11. 如何去除word文档中向下的箭头
  12. Redis数据存储类型
  13. gopher协议总结
  14. 精简指令集(RISC)和复杂指令集(CISC)的区别
  15. 鲜有人知道的项目,各种邀请码偷偷做几个W
  16. 超详细的WMS仓储管理系统介绍——盘点篇
  17. Java中内存问题之OOM 和SOF
  18. linux之getopt 函数
  19. 创始人退休后的Python,起飞还是没落?
  20. MongoDB体系结构

热门文章

  1. java-枚举类的定义及使用
  2. 对称多项式的牛顿公式即等幂和用初等多项式表示和证明
  3. RAID - 提升IO性能及数据安全
  4. 在HBuilderX上面新建微信小程序项目
  5. Matplotlib库简介
  6. Ubuntu/Win10双系统安全删除Ubuntu的方法
  7. css文字向右对齐_css怎么设置右对齐?
  8. 【bzoj1984】【坑】月下“毛景树” 树链剖分
  9. 董明珠接连直播背后:格力的线上焦虑
  10. macbook word插入公式快捷键 输入阿拉伯数字快捷键 快速打开访达快捷键