typescript 为什么DeepWriteable的品牌字符串/数字类型不再扩展字符串/数字?

0pizxfdo  于 2023-01-27  发布在  TypeScript
关注(0)|答案(1)|浏览(143)

我有一个DeepWriteable类型和一个品牌号码类型PositiveNumberPositiveNumber扩展了number,但是DeepWriteable<PositiveNumber>没有。品牌字符串类型也是如此。这里发生了什么?

type DeepWriteable<T> = { -readonly [P in keyof T]: DeepWriteable<T[P]> };
type PositiveNumber = number & { __brand: 'PositiveNumber' };
type NonEmptyString = string & { __brand: 'NonEmptyString' };

type test1 = PositiveNumber extends number ? true : false;
// TRUE
type test2 = DeepWriteable<PositiveNumber> extends number ? true : false;
// FALSE
type test3 = NonEmptyString extends string ? true : false;
// TRUE
type test4 = DeepWriteable<NonEmptyString> extends string ? true : false;
// FALSE

(BTW,我只询问品牌类型,因为常规numberstring似乎没有此行为)

type test5 = DeepWriteable<number> extends number ? true : false;
// TRUE
type test6 = DeepWriteable<string> extends string ? true : false;
// TRUE

我已经采取了只添加一个检查DeepWriteable不Map到numberstring的工作正常,但我很好奇为什么有必要。
是因为-readonly转换使它成为一个非同态Map类型吗?我想我也许可以理解为什么string会发生这种情况,因为lengthreadonly。在number上有类似的readonly属性吗?

e3bfsja2

e3bfsja21#

任何标记原语(与类对象类型相交的原语类型)上的mapped type(甚至是homomorphic)都将最终销毁该原语类型。
microsoft/TypeScript#12447中,规则的、非标记的原语上的同态Map类型是特殊情况,以返回不做任何更改的原语。
但是对于标记原语,您将获得输入类型的所有属性和表观属性的Map,这意味着DeepWriteable<PositiveNumber>将为您提供具有所有Number接口属性以及__brand属性的结果。
正如在相关问题microsoft/TypeScript#35992的评论中提到的:
用一个对象类型标记一个原语是一个你自己承担风险的奋进。基本上你可以这样做,只要类型从来没有经历过简化转换......也就是说,我描述的是当前的行为,而不是对未来行为的任何承诺。......我们确实在内部使用了一些标记,但是当我们遇到奇怪的时候,不要对我们自己提出错误😉
因此,看起来建议是避免对品牌原语进行过多的类型操作,或者至少彻底测试此类操作并调整它们,以处理当类型没有按您希望的方式组合时出现的任何意外问题。

相关问题