microsoft / microsoft/TypeScript
'identity' modifier to indicate a function's parameter-less returns should be narrowed like a value
Nadie ha tomado este issue todavía.
- Lenguaje dominante
- Go
- Estrellas
- 111k
- Forks
- 14.4k
- Merge medio
- 1 d 19 h
- PR fusionados (30 d)
- 117
Descripción
🔍 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.
Guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Línea de trabajo
Comienza con los ejemplos motivadores de TypeScript del issue y revisa las discusiones enlazadas de Angular y Solid, junto con el comentario de TypeScript referenciado. No se mencionan archivos del repositorio ni tests; para darlo por terminado sería necesario acordar un diseño para los tipos de funciones identidad, el comportamiento de narrowing, los parámetros y la invalidación antes de la implementación y la validación.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- typescript
- Área
- compilers
- Tipo de issue
- Nueva funcionalidad
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Estado de actividad
- Estancado
- Claridad
- Bastante claro
- Aptitud para principiantes
- 25/100