Added comments to explain the Typescript metaprogramming

This commit is contained in:
Matt Pharoah
2023-02-15 09:37:48 -05:00
parent f8d8291caa
commit d93e698baf

View File

@@ -1,16 +1,21 @@
import { LitElement } from 'lit';
import { property } from 'lit/decorators.js';
// Match event types that are registered on GlobalEventHandlersEventMap...
type EventTypeRequiresDetail<T> = T extends keyof GlobalEventHandlersEventMap
? GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, unknown>>
? GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, never>>
? // ...where the event detail is an object...
GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, unknown>>
? // ...that is non-empty...
GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, never>>
? never
: Partial<GlobalEventHandlersEventMap[T]['detail']> extends GlobalEventHandlersEventMap[T]['detail']
: // ...and has at least one non-optional property
Partial<GlobalEventHandlersEventMap[T]['detail']> extends GlobalEventHandlersEventMap[T]['detail']
? never
: T
: never
: never;
// The inverse of the above (match any type that doesn't match EventTypeRequiresDetail)
type EventTypeDoesNotRequireDetail<T> = T extends keyof GlobalEventHandlersEventMap
? GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, unknown>>
? GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, never>>
@@ -21,15 +26,22 @@ type EventTypeDoesNotRequireDetail<T> = T extends keyof GlobalEventHandlersEvent
: T
: T;
// `keyof EventTypesWithRequiredDetail` lists all registered event types that require detail
type EventTypesWithRequiredDetail = {
[EventType in keyof GlobalEventHandlersEventMap as EventTypeRequiresDetail<EventType>]: true;
};
// `keyof EventTypesWithRequiredDetail` lists all registered event types that do NOT require detail
type EventTypesWithoutRequiredDetail = {
[EventType in keyof GlobalEventHandlersEventMap as EventTypeDoesNotRequireDetail<EventType>]: true;
};
// Helper to make a specific property of an object non-optional
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
// Given an event name string, get a valid type for the options to initialize the event that is more restrictive
// than just CustomEventInit when appropriate (validate the type of the event detail, and require it to be
// provided if the event requires it)
type SlEventInit<T> = T extends keyof GlobalEventHandlersEventMap
? GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, unknown>>
? GlobalEventHandlersEventMap[T] extends CustomEvent<Record<PropertyKey, never>>
@@ -40,6 +52,7 @@ type SlEventInit<T> = T extends keyof GlobalEventHandlersEventMap
: CustomEventInit
: CustomEventInit;
// Given an event name string, get the type of the event
type GetCustomEventType<T> = T extends keyof GlobalEventHandlersEventMap
? GlobalEventHandlersEventMap[T] extends CustomEvent<unknown>
? GlobalEventHandlersEventMap[T]