microsoft / microsoft/TypeScript

Manually widen a type for conditional/mapped type

Aperta
#31,844 0 commenti 1 reazione 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Awaiting More Feedback Suggestion
Lingua principale
Go
Stelle
111k
Fork
14.3k
Merge medio
2g 4h
PR unite (30g)
132

Descrizione

Search Terms

manual widen

Suggestion

I would like some keyword or other mechanism to refer to the widened version of a type, e.g. widened 42 would be number and widened 'foo' would be string. Importantly, widened 42 & { foo: 'bar' } would be number & { foo: 'bar' }.

Use Cases

Our project uses a ton of branded primitives, which are accomplished by casting a number or string to number & Branding or string & Branding. We use this for all sorts of things: we have number & Pixels to indicate that a number is in pixels (and to force numbers passed to a function expecting pixels to use a number branded as pixels), we use string & Url to indicate a string is a URL, and so on.

We also have functions that operate on these types in a generic fashion, where we want to retain the branding. For example,

declare function plus<N extends number>(a: N, b: N): N;

This plus function is supposed to make sure we are adding pixels to pixels (or whatever unit), and retain the fact that their sum is also a number of pixels.

The problem comes in when we also have const offset = 5 as 5 & Pixels;. We define it as having that literal value for convenience (mostly, it shows up in Intellisense), and we have quite a few of these. More relevantly, the implementations of times and dividedBy (which I’m avoiding putting here as they are vastly more complex to cover canceling out units) can and should be able to take just plain numbers, but when I call times(offset, 2) it is inferred as times<Pixels, 2> and the return value retains the 2 even though obviously the runtime value is almost-certainly not going to be 2.

I asked for a solution to this on Stack Overflow, and was informed the only solution was to manually recreate the type by covering all of the potential brandings—which I basically have done, except that in the end there needs to be a generic overload, because we have a lot of situations where these functions are called by functions/classes that are also generic, and so only have N extends number, so the only overload available is the final one—which just retains whatever N was, even if N was a literal. I want to use widen N instead.

Examples

const c = 5 as const;
const w: widened typeof c = 3;

function plus<N extends number>(a: N, b: N): widened N {
    return a + b;
}
class Pixels { private '__ in': 'pixel'; }
const offset = 5 as 5 & Pixels;
declare const width: Pixels;

const offsetWidth = plus(width, offset); // Pixels, not 5 & Pixels

Checklist

My suggestion meets these guidelines:

  • 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, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Non vengono nominati file, test o punti di ingresso. Inizia studiando gli esempi widened richiesti e il comportamento esistente dei tipi condizionali e mappati, quindi determina come la proposta dovrebbe preservare le intersezioni e il branding; il lavoro è completo quando gli esempi superano il controllo dei tipi con i risultati ampliati, senza modificare il JavaScript emesso.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
typescript
Ambito
compilers
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
35/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.