TypeScript Design Meeting Notes, 6/7/2024

2fjabf4q  于 6个月前  发布在  TypeScript
关注(0)|答案(6)|浏览(61)

控制流程回调参数以及 Deferred 标记类型

#58729

  • 想要能够追踪回调作为控制流的可能分支。
  • 不幸的是,有很多回调是排队并以延迟方式运行的。
  • 需要一种方式来表示任何可能的函数调用都不会立即发生。
  • 我们采取的方法是将回调的类型 Package 在一个 Deferred<...> 帮助类型中。
  • 这需要更多的工作,那么我们是如何避免它的呢?
  • 我们引入了在 TS 5.5 中的一些关于折叠控制流图中无效果的部分的优化 - 这有所帮助。
  • 但现在还有大量的工作要做,解决被调用的函数以确定是否有任何参数被标记为 Deferred
  • 这种工作本来无论变量是否实际上在 lambda 中被引用都会完成。
doStuff(() => {
    x = 123;
});
y;
  • 在上面的示例中,我们的回调已知是有效果的 - 因此我们需要对其进行遍历以确定 y 的类型,即使 y 从不被引用。
  • 因此,而不是立即解析被调用函数的类型,我们在决定解析之前对回调的 CFG 进行遍历以查找对 y 的赋值。
  • 但是,如果你有一个有效函数,你不是必须解析调用吗?
  • 一个较少不必要的前期工作会触发更少的循环。
  • 但这并不一定是这样。 本地效果可能与外部变量无关!
let x = 0;
doStuff(() => {
    let y = 123;
    y = 456;
    return y;
});

x;
  • 在上面的示例中, y 被改变,但 x 本身从未被引用。
  • 当有多个重载时会发生什么 - 一个是延迟的?
  • 我们不会进行完整的重载解析 - 我们只是查找是否有任何签名在该位置具有 Deferred 类型。
  • 这很奇怪,因为这是一个内置类型,而不是与参数/绑定相关的东西。
  • 你可以在其他地方使用它吗?
  • 等等,你不能写类似 f(options: { f: Deferred<() => void> }) 的东西吗?
  • 你可以写,但它不起作用。
  • 如果 Deferred 是一个类型,你可以为延迟元组写 { [K in keyof T]: Deferred<T[K]> }
  • 然后将其传播开来?
  • ...这取决于你想何时解析。目前我们不做。
  • 这说明这更多是一种参数修饰符 - 因为你不希望给人留下这样的印象,即它可以用于 任何地方
  • 我们可以在某些地方禁止使用 Deferred
  • 目前只允许在参数中使用它,并在未来扩展。
  • 很高兴 Deferred<...> 没有新的语法,类似于 NoInfer
  • 回到开头 - 这个分析不仅仅是为了赋值,也是为了数组变异。
let a = [];
a.push("abc");

invoke(() => {
    a.push(123);
});

a; // Array<number | string>
  • 这是否跟踪了函数是否真正是延迟还是不是的问题?
  • 不,这不是一个简单的问题来真正回答。
  • 关于 await、别名等的复杂性。
  • 尽管这也引发了一些关于 Deferred 的问题。
let fns: Array<() => void> = [];
function enqueue(f: Deferred<() => void>) {
    // Is it okay to push a Deferred function in here?
    fns.push(f);
}

function runThem() {
    for (const f of fns) {
        f();
    }
}

let y: number | string = 0;
enqueue(() => {
    y = "abc";
})
y; // We correctly see that the narrowed type of 'y' is 'number' because we used 'Deferred'.

let x: number | string = 0;
enqueue(() => {
    x = "abc";
})
runThem();
x; // Because we wrote 'Deferred', we will *incorrectly* say that the narrowed type is 'number'.
  • 这在多大程度上取决于你如何严格地将 Deferred 视为“下一个事件循环”或“不是立即”的问题?
inn6fuwd

inn6fuwd1#

Deferred 辅助类型
难道不应该反过来吗?一个 NonDeferred 辅助类型?如果你把“非延迟”当作默认值,那么你最终会导致你试图避免的同样的问题(假设回调是延迟的,并且过早地取消了它的缩小)
此外,我认为立即调用回调的函数相对于延迟/异步调用的函数可能是少数。

nuypyhwy

nuypyhwy2#

我认为,立即调用回调函数的功能相对于延迟/异步调用的功能来说可能是少数。
...除非有人刚刚读完一个monad教程,在它终于对他们有意义时,他们感到非常兴奋🚎

4sup72z8

4sup72z83#

这个想法是将这个放在一个--strict标志后面,该标志对缩小持更保守的观点-并且声明站点可以选择退出。

yqyhoc1h

yqyhoc1h4#

嗯...似乎在今天,做类似的事情可能很符合习惯。
作为原则,我觉得在所有回调函数都被注册之前传递 foo 会让我感到不舒服,而且在我把这个建议的标志打开之前,库作者更新他们的类型以对齐是不可能的,这可能会让 strict 变得过于不稳定。
我的观点也适用于 DeferredNonDeferred 之间潜在的代码膨胀问题。

idfiyjo8

idfiyjo85#

我认为,相对于延迟调用或异步调用的回调函数,立即调用回调函数的函数可能属于少数。
我假设大多数回调函数是数组方法回调函数,仅供参考。

sg3maiej

sg3maiej6#

这对我来说是不可行的,直到图书馆编写者更新他们的类型以对齐,这可能会使它对于strict来说过于脆弱。
这也是我的担忧之一——人们会尝试这个功能,发现它太痛苦了,然后忘记在未来再次尝试打开它。

相关问题