Design Meeting Notes, 2026-09-01

未关闭
#64,129 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
25/100
Issue 类型
功能
描述清晰度
需要澄清
活跃度
活跃
技术栈
typescript
领域
api, compilers

调研方向

从链接的 TypeScript issue 63708 和条件分发示例开始,然后查看有关 binder 更改、替换类型和兼容性的注释。另行检查提议的 sync/async 和 AST 入口点,以及 top-999 原型计划。目前尚未定义实现范围或完成标准;原型和外部反馈是所述的下一步。

由索引模型根据 Issue 内容生成。

描述

Design Notes

Conditional Distributions Allow Constraint Violation

https://github.com/microsoft/TypeScript/issues/63708

type Issue<A, B extends A> =
    A extends unknown ?
        B extends unknown ?
            Show<A, B> :
        never :
    never;

type Show<A, B> = [A, B] & {};

type X = Issue<0 | 1, 0 | 1>;
//   ^?
  • The problem is that when we distribute on A and B, then we should create a new type parameter for each one with an identical name.

  • So we are prototyping this.

  • This is a little complicated by the fact that this now also becomes a declaration site rather than just a usage.

    • We would need to introduce something in the binder for this.
    • So that would say "this is a distribution site with a new type variable".
  • But that would have broader implications beyond just type variables on the left side of extends.

  • Doing something like this would changing the semantics of type distribution because we'd now operate over any identifier-named type.

    // TODO
    
  • When explaining to others, we've explained this as "there's a new type variable that is created for distribution", so surprised it didn't work this way.

    • Really there's a mix of substitution types and other instantiation mechanics at play here.
  • Do we need substitution types?

    • Yes. You need "learned information"/"conditional narrowing" to be tracked along to satisfy other constraints in true branches.
    • Wait really? Why can't T extends number become T' extends T & number?
  • How does this work over type references that alias bare identifiers

    type Foo<T> = T;
    
    type Blah<T> = Foo<T> extends any ? { b: Foo<T> } : undefined;
    
    type What = Blah<1 | 0>;
    
    • Today, this does distribute; it no longer would with the suggested change...
    • Oh... that's probably very breaky!
    • Who does this?
      • Someone, guaranteed.
  • Feels like people should at least have a way to distribute explicitly since we might be changing things here?

  • You are binding a new type parameter at the top; there's no reason you couldn't other than efficiency.

    • No - we use substitution types to track learned information and conditional narrowing.
    • There are differences in type comparisons when you have substitution types, and they differ in how they act on type comparisons.
    • So while they feel similar, type parameters with added constraints are treated differently in practice.
    • T'' extends T' & (1 | 2) extends T & number isn't reasoned about quite the same as T'' & (1 | 2) & number.
  • Why don't we just introduce syntax to avoid breaking people?

    • The problem is that we are trying to fix a soundness hole and we want that to be fixed by default.
  • Prototype will tell us what breaks in top 999.

API Bikeshed

import { version, versionMajorMinor } from "typescript";
import * as ts from "typescript/async"; // or sync
import * as ast from "typescript/ast";
  • Currently there's a bunch of subpath exports in the typescript package.
    • ast
    • factory
    • is
    • ...
  • As we prototyped replacements with the new API, we noticed old API usage was annoying to go through different imports.
    • Feedback from early API users is that it's less overwhelming than having one import with everything.
  • One of the things we don't like with the "siloing" is that it kind of draws boundaries that we might be fixing ourselves into.
    • Can't really have a single barrel given the sync/async split.

    • If you want a single barrel, you can do it yourself!

      // ./src/typescript.ts
      
      // Single barrel export for convenience
      export * from "typescript";
      export * from "typescript/ast";
      export * from "typescript/async";
      
      // package.json
      {
          // ...
          "imports": {
              "#ts": "./dist/typescript.js"
          }
      }
      
      // Other usage
      import * as ts from "#ts";
      
  • What about identical types imported through different paths?
    • e.g. ModuleKind comes from both "typescript" and "typescript/async".
    • What do people want from this?
  • Do the names overlap between sync/async modules?
    • Yes, they have identical names.
    • It'd be annoying if they all had an Async postifx.
  • Could we just simplify this all into typescript/async and typescript/sync, and re-export common stuff from both?
    • What do you do if you have a function that acts only on the common stuff?
    • Any AST walker.
  • Aside: do we have forEachChildAsync?
    • Currently a problem because forEachChild short-circuits on truthy results. Promises are always truthy, so a walk always exits early.
  • If we had the FIFO prototype resurrected (come back to this @JakeBailey?), would people even want async because the context switching is so high?
    • Async is just painful
    • But it's the only way to easily do things concurrently.
    • Wonder how easy it is to use workers and just use the sync layer.
  • Out of time - really need to build some prototypes and get feedback from others.
主要语言
Go
星标
111k
派生
14.4k
平均合并
1 天 19 小时
30 天内合并 PR
117

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

microsoft/TypeScript 的其他 Issue

查看 microsoft/TypeScript 的全部 Issue

相似的 Issue

更多 Go Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。