microsoft / microsoft/TypeScript
Manually widen a type for conditional/mapped type
Nessuno ha ancora preso questa issue.
- 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
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- 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