simplify type, add tests

pull/7224/head
Simon Holthausen 3 years ago
parent 61be96e34e
commit 8d5767497e

@ -90,7 +90,7 @@
},
"types": "types/runtime/index.d.ts",
"scripts": {
"test": "npm run test:unit && npm run test:integration",
"test": "npm run test:unit && npm run test:integration && ECHO \"manually check that there are no type errors in test/types by opening the files in there\"",
"test:integration": "mocha --exit",
"test:unit": "mocha --config .mocharc.unit.js --exit",
"quicktest": "mocha --exit",

@ -56,25 +56,14 @@ export function onDestroy(fn: () => any) {
get_current_component().$$.on_destroy.push(fn);
}
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void
? I
: never
type ExtractObjectValues<Object extends Record<any, any>> = Object[keyof Object]
type ConstructDispatchFunction<EventMap extends Record<string, any>, EventKey extends keyof EventMap> =
EventMap[EventKey] extends never | null
? (type: EventKey, detail?: null, options?: DispatchOptions) => boolean
: null extends EventMap[EventKey]
? (type: EventKey, detail?: EventMap[EventKey], options?: DispatchOptions) => boolean
: (type: EventKey, detail: EventMap[EventKey], options?: DispatchOptions) => boolean
type CreateDispatchFunctionMap<EventMap> = {
[Key in keyof EventMap]: ConstructDispatchFunction<EventMap, Key>
export interface EventDispatcher<EventMap extends Record<string, any>> {
<Type extends keyof EventMap>(
...args: [EventMap[Type]] extends [never] ? [type: Type, parameter?: null | undefined, options?: DispatchOptions] :
null extends EventMap[Type] ? [type: Type, parameter?: EventMap[Type], options?: DispatchOptions] :
undefined extends EventMap[Type] ? [type: Type, parameter?: EventMap[Type], options?: DispatchOptions] :
[type: Type, parameter: EventMap[Type], options?: DispatchOptions]): boolean;
}
type EventDispatcher<EventMap extends Record<string, any>> = UnionToIntersection<ExtractObjectValues<CreateDispatchFunctionMap<EventMap>>>
export interface DispatchOptions {
cancelable?: boolean;
}
@ -87,7 +76,16 @@ export interface DispatchOptions {
* [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent).
* These events do not [bubble](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture).
* The `detail` argument corresponds to the [CustomEvent.detail](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail)
* property and can contain any type of data.
* property and can contain any type of data.
*
* The event dispatcher can be typed to narrow the allowed event names and the type of the `detail` argument:
* ```ts
* const dispatch = createEventDispatcher<{
* loaded: never; // does not take a detail argument
* change: string; // takes a detail argument of type string, which is required
* optional: number | null; // takes an optional detail argument of type number
* }>();
* ```
*
* https://svelte.dev/docs#run-time-svelte-createeventdispatcher
*/

@ -0,0 +1,43 @@
import { createEventDispatcher } from '$runtime/internal/lifecycle';
const dispatch = createEventDispatcher<{
loaded: never
change: string
valid: boolean
optional: number | null
}>();
// @ts-expect-error: dispatch invalid event
dispatch('some-event');
dispatch('loaded');
dispatch('loaded', null);
dispatch('loaded', undefined);
dispatch('loaded', undefined, { cancelable: true });
// @ts-expect-error: no detail accepted
dispatch('loaded', 123);
// @ts-expect-error: detail not provided
dispatch('change');
dispatch('change', 'string');
dispatch('change', 'string', { cancelable: true });
// @ts-expect-error: wrong type of detail
dispatch('change', 123);
// @ts-expect-error: wrong type of detail
dispatch('change', undefined);
dispatch('valid', true);
dispatch('valid', true, { cancelable: true });
// @ts-expect-error: wrong type of detail
dispatch('valid', 'string');
dispatch('optional');
dispatch('optional', 123);
dispatch('optional', 123, { cancelable: true });
dispatch('optional', null);
dispatch('optional', undefined);
dispatch('optional', undefined, { cancelable: true });
// @ts-expect-error: wrong type of optional detail
dispatch('optional', 'string');
// @ts-expect-error: wrong type of option
dispatch('optional', undefined, { cancelabled: true });

@ -0,0 +1,16 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "../..",
"baseUrl": "../../",
"paths": {
"$runtime/*": ["src/runtime/*"]
},
// enable strictest options
"allowUnreachableCode": false,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"strict": true,
},
"include": ["."]
}
Loading…
Cancel
Save