microsoft / microsoft/TypeScript
Safe type assertion (upcast / widening) operator
Nessuno ha ancora preso questa issue.
- Lingua principale
- Go
- Stelle
- 111k
- Fork
- 14.4k
- Merge medio
- 1g 19h
- PR unite (30g)
- 117
Descrizione
🔍 Search Terms
as, satisfies, type assertion, type casting
✅ 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 feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ Suggestion
I suggest adding a safe type assertion operator, a kind of middle ground between current as and satisfies.
- Like
as, it should cast the expression to the asserted type - Like
satisfies, it should only allow assertion if the asserted type is wider than the expression type
Here's what it might look like:
type Foo = { a: number }
const foo1 = { a: 1 } as! Foo // OK. foo1: Foo
const foo2 = { a: 1, b: 2 } as! Foo // OK, foo2: Foo
const foo3 = { b: 2 } as! Foo // Error, { b: number } is not assignable to Foo
const foo4 = { } as! Foo // Error, {} is not assignable to Foo
📃 Motivating Example
For example, such operator will allow to safely give named types to expressions without declaring extra variables or helper functions.
Consider an async function f that returns an object of type Foo:
type Foo = { a: number }
const f = async () => ({ a: 1 })
I want the returned object to strictly be of Foo type, how do I enforce this?
- Hard code the return type
const f = async (): Promise<Foo> => ({ a: 1 })
The problem here is that I must write Promise<Foo> instead of just Foo, but the Promise part can be inferred just fine. In real world these generics can be arbitrarily complex.
- Declare a variable
const f = async () => {
const result: Foo = { a: 1 }
return result
}
This is better than retyping generics but still pretty verbose.
- Use a helper function
const safeAssert = <T>(value: T): T => value
const f = async () => safeAssert<Foo>({ a: 1 })
This is ok but still requires writing/importing helper functions.
as is not an option here because it's unsafe, satisfies is neither because it doesn't name the type. Naming a type can be important for documentation purposes, this proposal allows to do this with less boilerplate.
const f = async () => ({ a: 1}) as! Foo // f: () => Promise<Foo>
💻 Use Cases
As described above, this feature can be used to safely cast expressions to specified types. A practical example when it can be useful is naming a type in an expression. Currently this is only covered by custom helper functions such as <T>(value: T): T => value.
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
La issue propone una nuova sintassi as! e fornisce esempi di widening assertions, incluso il caso asincrono Foo. Non vengono indicati file sorgente, test o entry point del compilatore, quindi inizia individuando la gestione esistente di as e satisfies nel codebase TypeScript. Il lavoro è completo quando la sintassi impone la regola di assignability proposta, produce i tipi inferiti dichiarati e non modifica 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à
- Tranquilla
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100