-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: Narrow Discriminated Unions by discarding types with no possible values #13300
Comments
Isn't |
@akarzazi sure, if you create a type name for each possible event (note each "subtype" in the type EventA = {eventName : "EVENT_A", dataA : any, confidentialDataA : any}
type EventB = {eventName : "EVENT_B", dataB : any, confidentialDataB : any}
type EventC = {eventName : "EVENT_C", superConfidentialDataC : any}
type Event = EventA | EventB | EventC
// Events ready for transfer, stripped from confidential data and maybe with other info
type SecurizedEventA = {eventName : "EVENT_A", dataA : any, otherDataA : any}
type SecurizedEventB = {eventName : "EVENT_B", otherDataB : any}
// C not possible, too confidential!
type SecurizedEvent = SecurizedEventA | SecurizedEventB
function securize<E extends Event>(e : E) : SecurizedEvent & {eventName : E["eventName"]} {
....
}
let e1 : EventB
let se1 = securize(e1) // type: SecurizedEventB
let e2: EventC
let se2 = securize(e2) // error! In any case, I don't see why this can't be implemented, and I think is good to exploit every possible opportunity to narrow DU's. |
Why would this fail ? type Event = EventA | EventB | EventC
//...
let e2: EventC
let se2 = securize(e2) // error! since securize accepts Event function securize<E extends Event>(e : E) : SecurizedEvent & E["eventName"] {
....
} |
@akarzazi: Sorry, that signature was wrong, I edited my example and corrected it. Must fail because it has no possible return value. |
Note, with this feature and mapped types you can define a fully typed type Event = ({eventName : "EVENT_A", dataA : any} |
{eventName : "EVENT_B", dataB : any})
function addEventHandler<T extends Event['eventName']>(eventName : T, cb : (evt : Event & {eventName : T}) => any) {
this.on(eventName, cb)
}
function handleA(evt : Event & {eventName : 'EVENT_A'}) {
evt.dataB // Compile error, invalid
evt.dataA // Ok, evt is correctly narrowed
}
addHandler('EVENT_A', handleA); // OK
addHandler('EVENT_B', handleA); // Compile error
|
I ran into this limitation as well, while trying to define a generic As you can see, the blocker that I run into is ultimately that TypeScript won't simplify a type like
|
I was able to come up with a modified, slightly more verbose idiom for declaring case classes that I'm going to proceed with, which features a correctly-typed
|
looks like the same issue as #18210 |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
It will be nice if TS narrowed Discriminated Unions by discarding types with no possible values (e.g.
{tag: 'a' & 'b', x : 1}
).Example:
Use case:
This comes from the discussion at #13203
The text was updated successfully, but these errors were encountered: