typescript type 分配条件类型

比特织月人
• 阅读 605

接上文type challenge(easy部分)
关于分配条件类型,官方文档描述地址

之前看的时候没真正理解,关于联合类型的分配条件,官方文档其实也没有讲得很明白,和翻译无关,英文文档一样很模糊,这些天做type challenge,发现有些题做出来的结果和预期不太一致,所以重新梳理这块内容。

先说结论

联合类型什么时候会分配,必须符合4个条件(后面直接用条件1、条件2等代指下面条件):

  1. 首先,只分配extends前的内容

    • 无论这个extends是不是子断言语句中的
    • 例如type Test<T> = 'b' extends 'b' ? (T extends 'b' ? true: false) : false;, 其中的T extends 'b'在子语句中,但事实上依旧是有效的
  2. 分配的内容未做任何处理

    • type Test<T> = keyof T extends null ? never: false;Tkeyof操作符处理了,因此不会分配
    • 官方文档中,提到避免分配的方法type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;,能规避分配也是这个道理
  3. 分配内容必须作为参数传入
  4. 传入时是联合类型

相关题目与解析

验证条件1

type Test<T> = 'b' extends 'b' ? (T extends 'b' ? true: false) : false;
Test<'a'| 'b'> // boolean

可见在子条件中的extends也符合自动分配,否则'a'|'b' extends 'b'会返回false,而不是true|false

验证条件2

发现这个问题是在DeepReadonly,题目地址

这一题一看看过去,直接写出如下:

type DeepReadonly<T> = keyof T extends never ? T : {readonly [k in keyof T]: DeepReadonly<T[k]>};

但是发现对于测试用例X2不生效

type X2 = { a: string } | { b: number };
DeepReadonly<X2> // { a: string } | { b: number }

仔细看,虽然X2是联合类型,但keyof T extends never显然不符合前面说的条件2,因此不会自动分配,而keyof ({ a: string } | { b: number })值为never。因此该题正确写法如下:

type DeepReadonly<T> = {
  readonly [P in keyof T]: keyof T[P] extends never ? T[P] : DeepReadonly<T[P]>;
};

验证条件3

显然,普通使用extands不会触发自动分配

type Test = 'a'|'b' extends 'a' ? true: false; // false

那么,假设传入的参数是联合类型,extends前的对象也是联合类型呢?

type Test<T> = 'b' extends 'b' ? (keyof T extends 'b' ? true: false) : false;
type Result = Test<{a:1,b:string}|{a:2,b:number}> // false

这里,参数T是联合类型,但extends前进行了keyof处理,但keyof {a:1,b:string}|{a:2,b:number}结果为'a'|'b',依然是联合类型,若这里进行了自动分配,结果应是boolean而非false

根据结果来看,这里并未进行分配,这个例子同时违背了条件2条件3

验证条件4

type Test<T> = 'a'|'b' extends 'b' ? T: false;
Test<5> // false

条件4显而易见,官方文档上已经说的很明确了。

不注意优先级导致的错误

在测试分配条件类型的规律时,曾因为一条用例卡了半天,用例如下:

type A = keyof null|undefined; // undefined
type UndefinedExtendsNull = undefined extends null ? true: false; //false
type Test<T> = keyof T extends null ? true: false;
Test<null|undefined>; // true !!!!

此时已经知道了,keyof T会避免自动分配,因此对于Test<null|undefined>,可以写成

keyof null|undefined extends null ? true : false; // 这里有个坑...

keyof null|undefined结果是undefined,但是

type UndefinedExtendsNull = undefined extends null ? true: false; //false

结果是false,同样的式子,结果不一样,一开始我以为是分配规律的理解有问题,但即使分配了,结果也应该是true|false,也就是boolean,而不是true

后来发现,type是有优先级的,且keyof优先级高于|.

按理说keyof null|undefined结果应该是never,之所以会显示结果是undefined,是因为优先级运算:

keyof null|undefined -> (keyof null)|undefined -> never|undefined -> undefined

在实际写类型的时候,要重点注意优先级问题

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Easter79 Easter79
3年前
typeScript数据类型
//布尔类型letisDone:booleanfalse;//数字类型所有数字都是浮点数numberletdecLiteral:number6;lethexLiteral:number0xf00d;letbinaryLiteral:number0b101
Stella981 Stella981
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
ELK学习笔记之配置logstash消费kafka多个topic并分别生成索引
0x00 filebeat配置多个topicfilebeat.prospectors:input_type:logencoding:GB2312fields_under_root:truefields:添加字段
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Easter79 Easter79
3年前
SpringBoot整合Redis乱码原因及解决方案
问题描述:springboot使用springdataredis存储数据时乱码rediskey/value出现\\xAC\\xED\\x00\\x05t\\x00\\x05问题分析:查看RedisTemplate类!(https://oscimg.oschina.net/oscnet/0a85565fa
Wesley13 Wesley13
3年前
ThinkPHP 根据关联数据查询 hasWhere 的使用实例
很多时候,模型关联后需要根据关联的模型做查询。场景:广告表(ad),广告类型表(ad\_type),现在需要筛选出广告类型表中id字段为1且广告表中status为1的列表先看关联的设置部分 publicfunctionadType(){return$thisbelongsTo('A
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
比特织月人
比特织月人
Lv1
昔我往矣,杨柳依依;今我来思,雨雪霏霏。
文章
2
粉丝
0
获赞
0