TypeScript 条件类型与属性链接断开

3mpgtkmj  于 2022-10-29  发布在  TypeScript
关注(0)|答案(7)|浏览(140)

**类型脚本版本:**3.5.1
搜索词:

属性链接,通用,对象类型参数,条件类型

代码

修改版本的@fatcerberus '试图打破TS。

type Droste<T extends {x:number|string}> = {
    value: T,
    /**

* Should alternate between string and number
* /

    droste: Droste<{x:(T["x"] extends number ? string : number)}>
};

declare const droste: Droste<{x:number}>;

//number
const _0 = droste.droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
    .droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
    .droste.droste;
const _1 = _0.droste; //string
const _2 = _1.droste; //number
const _3 = _2.droste; //string

const _4 = _3.droste; //Expected number, actual string, ???
const _5 = _4.droste; //string
const _6 = _5.droste; //string
const _7 = _6.droste; //string
const _8 = _7.droste; //string
const _9 = _8.droste; //string
//string forever and ever. Where is `number`?

预期行为:

每次访问.droste时,应在stringnumber之间交替进行。
或给予最大示例化深度/计数错误。

实际行为:

它在stringnumber之间交替,然后在一段时间后中断。
从这一点上说,它只是坚持与string
未给出错误。

Playground链接:

Playground

相关问题:

它类似于#32707
但是,它放弃并将型别解析为string,而不是any

atmip9wb

atmip9wb1#

我知道,我知道,递归式别名,不好。
接口也会中断,

interface Droste<T extends {x:number|string}> {
    value: T,
    /**

* Should alternate between string and number
* /

    droste: Droste<{x:(T["x"] extends number ? string : number)}>
};

declare const droste: Droste<{x:number}>;

//number
const _0 = droste.droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
    .droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
    .droste.droste;
const _1 = _0.droste; //string
const _2 = _1.droste; //number
const _3 = _2.droste; //string

const _4 = _3.droste; //number
const _5 = _4.droste; //Expected string, actual number, ???
const _6 = _5.droste; //number
const _7 = _6.droste; //number
const _8 = _7.droste; //number
const _9 = _8.droste; //number
//number forever and ever. Where is `string`?

Playground
不过,它的断裂方式不同。

rsl1atfo

rsl1atfo2#

看起来它与示例化限制冲突

type check<T> = T extends Droste<{ x: string }> ? true : false;
type a = check<typeof _1>; // true
type b = check<typeof _2>; // false 
type c = check<typeof _3>; // Type instantiation is excessively deep and possibly infinite.
insrf1ej

insrf1ej3#

32707(注解)中概述的解决方法似乎有效,

/**

* Uses the workaround discovered here,
* https://github.com/microsoft/TypeScript/issues/32707#issuecomment-518347966
* 
* Now, everything resolves correctly.
* /

type NextDrosteFix<X extends number|string> = (
    Droste<{x:(X extends number ? string : number)}>
);
type NextDroste<T extends {x:number|string}> = (
    NextDrosteFix<T["x"]>
);
interface Droste<T extends {x:number|string}> {
    value: T,
    /**

* Should alternate between string and number
* /

    droste: NextDroste<T>
};

declare const droste: Droste<{x:number}>;

//number
const _0 = droste.droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
    .droste.droste.droste.droste.droste.droste.droste.droste.droste.droste
    .droste.droste;
const _1 = _0.droste; //string
const _2 = _1.droste; //number
const _3 = _2.droste; //string

const _4 = _3.droste; //number
const _5 = _4.droste; //string
const _6 = _5.droste; //number
const _7 = _6.droste; //string
const _8 = _7.droste; //number
const _9 = _8.droste; //string

Playground
我知道这很管用但我不知道为什么会管用

snvhrwxg

snvhrwxg4#

如果我不得不猜测(这确实是一个猜测),在类型id上有一个示例化的缓存。在原始示例中,您为每个没有缓存值的递归示例化创建了一个新的对象文字类型(具有新的id)。
在修改后的示例中,每个递归都经过NextDrosteFix,该NextDrosteFix是用基元类型示例化的(并且基元类型是内部的)。NextDrosteFix将被缓存以用于stringnumber处的示例化。

7lrncoxx

7lrncoxx5#

数组类型是否也被认为是用于实习目的的基元类型?
数组类型似乎永远不会给予问题。只有对象文字类型。
[编辑]
对象常值型别、界面和类别(当做为型别参数条件约束使用时)

cx6n0qe3

cx6n0qe36#

我认为数组和元组是缓存的,但我会等待确认。

相关问题