热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用typescript推导已有变量的盲盒类型详情_javascript技巧

这篇文章主要介绍了使用typescript推导已有变量的盲盒类型详情,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要

迁移盲盒

当我们从Javascript一键转换Typescript的时候,any便是最省事的做法,对于维护并不友好(虽然能跑就行),同时每个变量对于我们来说都是盲盒,它到底是什么类型?

类型推导

基础类型的推导

基础数据类型的类型推导还是挺简单的

let a = 1;
type A = typeof a; // number;
let b = '2'
type B = typeof b; // string;
let c;
type C = typeof c; // undefined;

一个typeof就可以把原始值类型推导出来了!

我们整理下基础数据类型有哪些?

// 没错,7种数据类型
type Base = string | number | boolean | null | undefined | symbol | bigint;

对象的推导

这里我们来实现下普通对象如何推导

let obj = { a: 1, b: '2', c: true, d: null };
type Obj = typeof obj;
// { a: number; b: string; c: boolean; d: null; }

没错,也是这么简单!

数组的推导

为什么上面的对象除开数组呢?因为数组在typescript比较特殊,既可以用元祖来声明,又可以用数组来声明

也可以说数组包含了元祖

type isCOntain= [1, 2] extends Array ? true : false; // true

尝试继续通过typeof来实现推导

let arr = [1, '2', null, false];
type Arr = typeof arr; // (string | number | boolean | null)[] ???
type Arr1 = typeof arr[0] // string | number | boolean | null ???

好吧,得到的竟然是联合类型数组,是不是和我们预期的不一样?

我们定义一个数组,却没有声明类型,对于数组来说,默认就是 Array,由于不断填充了 number,string,null,boolean的值,最后变成了 Array,而且是每一个元素都是联合类型

重新整理下,我们需要的是啥?

[1, '2', null, false] -> [number, string, null, boolean]

我们要的是元祖 [number, string, null, boolean],而不是数组 Array

整理下todo,我们需要的是:


  • 固定长度的数组类型

  • 每个元素都有独立的类型


let arr = [1, '2', null, false] as const;
type Arr = typeof arr; // readonly [1, '2', null, false]
type Arr1 = typeof arr[0] // 1

第一个 todo 实现了,第二个有点像,但又不对,我们要的是数据类型,而不是某个具体的值

实现一个转换类型的泛型

我们要的是 1 转 number, 'A' 转 string,只需要列出所有的基础类型做转换就可以了

type GetType = T extends string ? string :
T extends number ? number :
T extends boolean? boolean :
T extends null ? null :
T extends undefined ? undefined :
T extends symbol ? symbol :
T extends bigint ? bigint : T;
type Arr1 = typeof arr[0] // number
type Arr2 = typeof arr[1] // string

那再遍历一次元祖就可以实现整个数组的类型转换了

type TransArr,
R extends unknown[] = []> = {
'loop': TransArr [...R,
T extends Base ?
GetType: T[R['length']]
]
>,
'result': R,
}[T['length'] extends R['length'] ? 'result': 'loop'];
let arr = [1, '2', null, false] as const;
type Arr = typeof arr;
type ArrType = TransArr; // [number, string, null, boolean]

函数的推导

函数的推导其实没有必要,为什么这么说,函数参数和值类型不可控,除个别操作符或者明确类型

如 (a, b) => a * b ,返回值一定是number

如 (a) => Promise.resolve(a),返回值一定是Promise

let fn1 = (a, b) => a * b;
type Fn1 = typeof fn1; // (a: any, b: any) => number
function fn2(a) {
return Promise.resolve(a);
}
type Fn2 = typeof fn2; // (a: any) => Promise

大多是函数经过typeof后得到的结果是

(a: any, b: any, ...) => any;

这个类型可以限定参数数量更多的函数

function fn3(a, b, c) {
return a + b + c;
}
function fn4(d) {
return d + 1;
}
type Fn3 = typeof fn3; // (a: any, b: any, c: any) => any
type Fn4 = typeof fn4; // (d: any) => any
type F3_4 = Fn3 extends Fn4 ? true : false; // false
type F4_3 = Fn4 extends Fn3 ? true : false; // true

也就是说,参数多的函数总是包含了参数少的函数

根据上面的判断,我们可以通过这个来实现函数的判断

type isFunc = (() => any) extends T ? true : false;

完善推导



  • 基础类型直接返回类型

  • 数组用TransArr泛型转一次

  • 函数直接返回typeof的值

  • 遍历对象则用keyof实现


type Trans = T extends Base
? GetType : T extends Array
? TransArr : isFunc extends true
? T : {
[key in keyof T]: T[key] extends Base
? GetType : T[key] extends Array
? TransArr : Trans;
};

测试


let a1 = 1;
type test1 = Trans; // number
let a2 = '2';
type test2 = Trans; // string
let a3 = [1, '2', true, '3', 4] as const;
type test3 = TransArr;
// [number, string, boolean, string, number]
let a4 = {
a: 1,
b: true,
c: {
a: 1,
b: [1, '2']
},
d: [true, null]
} as const;
type test4 = Trans;
// {
// readonly a: number;
// readonly b: boolean;
// readonly c: {
// readonly a: number;
// readonly b: readonly [number, string];
// };
// readonly d: readonly [boolean, null];
// }
let a5 = {
a: [
{
b: [
{ c: 1 }
]
}
]
} as const;
type test5 = Trans;
// {
// readonly a: readonly [{
// readonly b: readonly [{
// readonly c: number;
// }];
// }];
// }
let a6 = (a, b, c) => a + b + c;
type test6 = Trans;
// (a: any, b: any, c: any) => any
let a7 = [
function fn() {
return 1;
},
(a, b) => a * b,
(a) => Promise.resolve(a)
] as const;
type test7 = TransArr;
// [() => number, (a: any, b: any) => number, (a: any) => Promise]
let a8 = {
a: 1,
b: [true, null],
c: [() => void, (a, b) => a],
d: {
e: [
(a, b) => null,
{
f: [1]
}
]
}
} as const;
type test8 = Trans;
// {
// readonly a: number;
// readonly b: readonly [boolean, null];
// readonly c: readonly [() => undefined, (a: any, b: any) => any];
// readonly d: {
// readonly e: readonly [(a: any, b: any) => null, {
// readonly f: readonly [number];
// }];
// };
// }


推荐阅读
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
author-avatar
余温
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有