microsoft / microsoft/TypeScript
'identity' modifier to indicate a function's parameter-less returns should be narrowed like a value
まだ誰も着手していません。
- 主要言語
- Go
- スター
- 111k
- フォーク
- 14.4k
- 平均マージ
- 1日 19時間
- マージ済み PR(30日)
- 117
説明
🔍 Search Terms
indicate function returns identical value cached memoized signals
✅ Viability Checklist
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This isn't a request to add a new utility type: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ Suggestion
Many apps today are built on the concept of using small "getter" functions as wrappers around values. For example, Signals as implemented in Angular, Solid, and the stage 1 TC39 Signals proposal often look something like:
declare const value: () => string | undefined;
if (value() !== undefined) {
console.log(value().toUpperCase());
}
Signals users have struggled with using them in TypeScript because, at present, there isn't a way to get that code block to type check without type errors. Signals users know that the result of value() must be string inside the if, but TypeScript doesn't have a way to note that the result should be type narrowed. Common workarounds today include !, ?., and refactoring to store intermediate values. All of which are at best unnecessary verbosity, and at worst conflict with frameworks.
Request: can we have a keyword -or, failing that, built-in / intrinsic type- to indicate that calls to a function produce a referentially equal, structurally unchanging value? In other words, that the function call (value()) should be treated by type narrowing as if it was just a variable reference (value)?
Proposal: how about an identity modifier keyword for function types that goes before the ()? It would be treated in syntax space similarly to other modifier keywords such as abstract and readonly.
📃 Motivating Example
When an identity function is called, it is given the same type narrowing as variables. Code like this would now type check without type errors, as if value was declared as const value: string | undefined:
declare const value: identity () => string | undefined;
if (value() !== undefined) {
value();
// Before: string | undefined
// Now: string
console.log(value().toUpperCase());
// Before: ~~~~~~~ Object is possibly 'undefined'.
// Now: ✅
}
Narrowing would be cleared the same as variables when, say, a new closure/scope can't be guaranteed to preserve narrowing:
declare const value: identity () => string | undefined;
if (value() !== undefined) {
setTimeout(() => {
value();
// Still: string | undefined
console.log(value().toUpperCase());
// Still: ~~~~~~~ Object is possibly 'undefined'.
});
}
💻 Use Cases
One difficult-to-answer design question is: how could identity handle functions with parameters? I propose the modifier not be allowed on function signaturess with parameters to start. It should produce a type error for now. The vast majority of Signals users wouldn't need signatures with parameters, so I don't think solidifying that needs to block this proposal. IMO that can always be worked on later.
Furthermore, it's common for frameworks to set up functions with a parameter-less "getter" signature and a single-parameter "setter" signature. I propose for an initial version of the feature, calling any other methods or setting to any properties on the type should clear type narrowing:
declare const value: {
identity (): string | undefined;
(newValue: string | undefined): void;
}
if (value() !== undefined) {
value("...");
value();
// Still: string | undefined
console.log(value().toUpperCase());
// Still: ~~~~~~~ Object is possibly 'undefined'.
}
More details on the difficulties of signals with TypeScript:
- Angular: https://github.com/angular/angular/issues/49161
- Solid: https://github.com/solidjs/solid/discussions/1575
If a new modifier keyword isn't palatable, a fallback proposal could be a built-in type like Identity<T>. This wouldn't be a new utility type (FAQ: no new utility types); it'd be closer to the built-in template string manipulation types.
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
Issue にある動機となる TypeScript の例から始め、リンクされている Angular と Solid の議論、および参照されている TypeScript のコメントを確認してください。リポジトリのファイルやテストは指定されていません。実装と検証に先立ち、identity function の型、narrowing の挙動、パラメーター、invalidiation について合意された設計が必要です。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- typescript
- 領域
- compilers
- issue の種類
- 機能追加
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 停滞
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 25/100