microsoft / microsoft/TypeScript

Suggestion: Distributive code inference "as dist"

未关闭
#62,631 3 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

Awaiting More Feedback Suggestion
主要语言
Go
星标
111k
派生
14.3k
平均合并
2 天 4 小时
30 天内合并 PR
132

描述

### 🔍 Search Terms

- distributive inference
- distributed function
- as dist
- as distributed

### ✅ Viability Checklist

- [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
- [x] This wouldn't change the runtime behavior of existing JavaScript code
- [x] This could be implemented without emitting different JS based on the types of the expressions
- [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- [x] This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- [x] This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

### ⭐ Suggestion

Add `dist` / `distributed` keyword to enable inference in a distributive manner.

### Concept 1: Inline `as dist`

Handle the inference by distributing over all types used by the expression:

```ts
const transform = (val: [1, 1] | [2, 2]) => [val[0], val[1]] as dist;
typeof transform; // (val: [1, 1] | [2, 2]) => [1, 1] | [2, 2]

//

const add = (...[a, b]: [number, number] | [bigint, bigint]) => a + b as dist;
typeof add; // (...[a, b]: [number, number] | [bigint, bigint]) => number | bigint
```

### Concept 2: Function-level `dist` return type

Allow distribution across an entire function body:

```ts
const f = (...[a, b]: T): dist => {
const sum = a + b; // number | bigint
const arr = [a, b]; // [number, number] | [bigint, bigint];
return {
sum,
arr
} // {sum: number, arr: [number, number]} | {sum: bigint, arr: [bigint, bigint]}
}

const res = f(3,7); // {sum: number, arr: [number, number]}
const rez = f(3n,7n); // {sum: bigint, arr: [bigint, bigint]}

typeof f; // ((...[a, b]: T) => { sum: number; arr: [number, number]; }) & ((...[a, b]: T) => { sum: bigint; arr: [bigint, bigint]; })
```

Concept 1 could also be supported on function expressions with equivalent behavior to Concept 2:

```ts
const f2 = ((...[a, b]: T) => {/*code*/}) as dist; // Equivalent to "f"
```

### Notes

These are early-stage concepts meant to illustrate the core idea. The specific syntax and behaviors should be refined during implementation.

**Open questions:** Interaction with `as const`, generics, nested functions, opt-out mechanisms, etc. will need consideration.
**Potential breaking change:** Codebases with a type called `dist` would conflict, though this would go against TypeScript's PascalCase naming convention for types.

### 📃 Motivating Example

Currently, code is inferred in a non-distributive manner:

> Example inspired by [geon](https://www.reddit.com/user/geon/)
```ts
const transform = (val: [1, 1] | [2, 2]) => [val[0], val[1]] as const;
// Inferred return type: readonly [1 | 2, 1 | 2]
// Expected return type: readonly [1, 1] | readonly [2, 2]
```

This can be addressed by duplicating your code logic within a distributive context in the typesystem:

```ts
const transform = (val: T) => [val[0], val[1]] as T extends unknown
? [T[0], T[1]]
: never
;

const res = transform(undefined! as [1, 1] | [2, 2]); // [1, 1] | [2, 2]
const rez = transform([1, 1]); // [1, 1]
```

But this is very repetitive and awkward. Besides that, this only works if the automatic inference doesn't cause a conflict to begin with and can be simply translated into the type system:

> Example inspired by [Emilio Platzer](https://github.com/emilioplatzer) and Mudloop
```ts
// @ts-expect-error: Operator '+' cannot be applied to types 'number | bigint' and 'number | bigint'.(2365)
const add = (...[a, b]: [number, number] | [bigint, bigint]) => a + b;
```

### 💻 Use Cases

1. What do you want to use this for?
Preserving precise type relationships when transforming union types, and enabling operations across union branches that are currently rejected by the type checker.
2. What shortcomings exist with current approaches?
Current workarounds require manually duplicating code logic in the type system using conditional types. This is verbose, error-prone, and fails when TypeScript rejects the runtime-aligned code itself
3. What workarounds are you using in the meantime?
Manually encoding distributive logic using conditional types

贡献指南

打开贡献指南

从这里开始

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

调研方向

尚未确定任何实现文件、测试或编译器入口点。首先审查两种提议的语法、作为动机的示例,以及围绕泛型、嵌套函数和 opt-outs 的未决问题。只有先确定设计、再划定实现范围,才算完成。

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

评估

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

把新 issue 发到你的邮箱

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