Skip to content

Commit

Permalink
fix some typings
Browse files Browse the repository at this point in the history
  • Loading branch information
edoardocavazza committed Jun 28, 2023
1 parent e4aa98b commit a4c6d61
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 73 deletions.
2 changes: 1 addition & 1 deletion .changeset/eighty-hounds-leave.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"@chialab/dna": patch
---

cleanup component class typings
Cleanup component class typings
34 changes: 12 additions & 22 deletions src/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ export type WithComponentProto<T> = T & {
* We use this mixin to cast the Component class constructor in order to preserve type definition.
*/
export interface ComponentMixin {
/**
* Type getter for component properties.
*/
readonly __properties__: Props<this>;

/**
* Type getter for JSX properties.
*/
Expand Down Expand Up @@ -72,7 +67,7 @@ export interface ComponentMixin {
* @param oldValue The previous value of the property.
* @param newValue The new value for the property (undefined if removed).
*/
stateChangedCallback<P extends keyof this['__properties__']>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]): void;
stateChangedCallback<P extends keyof this>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]): void;

/**
* Invoked each time one of a Component's property is setted, removed, or changed.
Expand All @@ -81,39 +76,39 @@ export interface ComponentMixin {
* @param oldValue The previous value of the property.
* @param newValue The new value for the property (undefined if removed).
*/
propertyChangedCallback<P extends keyof this['__properties__']>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]): void;
propertyChangedCallback<P extends keyof this>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]): void;

/**
* Get the inner value of a property.
* This is an helper method for properties getters and setters.
* @param propertyName The name of the property to get.
* @returns The inner value of the property.
*/
getInnerPropertyValue<P extends keyof this['__properties__']>(propertyName: P): this[P];
getInnerPropertyValue<P extends keyof this>(propertyName: P): this[P];

/**
* Set the inner value of a property.
* This is an helper method for properties getters and setters.
* @param propertyName The name of the property to get.
* @param value The inner value to set.
*/
setInnerPropertyValue<P extends keyof this['__properties__']>(propertyName: P, value: this[P]): void;
setInnerPropertyValue<P extends keyof this>(propertyName: P, value: this[P]): void;

/**
* Observe a Component Property.
*
* @param propertyName The name of the Property to observe
* @param observer The callback function
*/
observe<P extends keyof this['__properties__']>(propertyName: P, observer: PropertyObserver<this[P]>): void;
observe<P extends keyof this>(propertyName: P, observer: PropertyObserver<this[P]>): void;

/**
* Unobserve a Component Property.
*
* @param propertyName The name of the Property to unobserve
* @param observer The callback function to remove
*/
unobserve<P extends keyof this['__properties__']>(propertyName: P, observer: PropertyObserver<this[P]>): void;
unobserve<P extends keyof this>(propertyName: P, observer: PropertyObserver<this[P]>): void;

/**
* Dispatch a custom Event.
Expand Down Expand Up @@ -334,11 +329,6 @@ function initSlotChildNodes<T extends HTMLElement, C extends ComponentInstance<T
*/
const mixin = <T extends HTMLElement>(ctor: Constructor<T>) => {
const Component = class Component extends (ctor as Constructor<HTMLElement>) {
/**
* Type getter for component properties.
*/
declare readonly __properties__: Props<this>;

/**
* Type getter for JSX properties.
*/
Expand Down Expand Up @@ -544,7 +534,7 @@ const mixin = <T extends HTMLElement>(ctor: Constructor<T>) => {
* @param oldValue The previous value of the property.
* @param newValue The new value for the property (undefined if removed).
*/
stateChangedCallback<P extends keyof this['__properties__']>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]) {
stateChangedCallback<P extends keyof this>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]) {
reflectPropertyToAttribute(this, propertyName, newValue);
}

Expand All @@ -555,7 +545,7 @@ const mixin = <T extends HTMLElement>(ctor: Constructor<T>) => {
* @param oldValue The previous value of the property.
* @param newValue The new value for the property (undefined if removed).
*/
propertyChangedCallback<P extends keyof this['__properties__']>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]) {
propertyChangedCallback<P extends keyof this>(propertyName: P, oldValue: this[P] | undefined, newValue: this[P]) {
reflectPropertyToAttribute(this, propertyName, newValue);
}

Expand All @@ -565,7 +555,7 @@ const mixin = <T extends HTMLElement>(ctor: Constructor<T>) => {
* @param propertyName The name of the property to get.
* @returns The inner value of the property.
*/
getInnerPropertyValue<P extends keyof this['__properties__']>(propertyName: P): this[P] {
getInnerPropertyValue<P extends keyof this>(propertyName: P): this[P] {
const property = getProperty(this, propertyName, true);
return this[property.symbol as keyof this] as this[P];
}
Expand All @@ -576,7 +566,7 @@ const mixin = <T extends HTMLElement>(ctor: Constructor<T>) => {
* @param propertyName The name of the property to get.
* @param value The inner value to set.
*/
setInnerPropertyValue<P extends keyof this['__properties__']>(propertyName: P, value: this[P]) {
setInnerPropertyValue<P extends keyof this>(propertyName: P, value: this[P]) {
const property = getProperty(this, propertyName, true);
this[property.symbol as keyof this] = value;
}
Expand All @@ -587,7 +577,7 @@ const mixin = <T extends HTMLElement>(ctor: Constructor<T>) => {
* @param propertyName The name of the Property to observe
* @param observer The callback function
*/
observe<P extends keyof this['__properties__']>(propertyName: P, observer: PropertyObserver<this[P]>) {
observe<P extends keyof this>(propertyName: P, observer: PropertyObserver<this[P]>) {
addObserver(this, propertyName, observer);
}

Expand All @@ -597,7 +587,7 @@ const mixin = <T extends HTMLElement>(ctor: Constructor<T>) => {
* @param propertyName The name of the Property to unobserve
* @param observer The callback function to remove
*/
unobserve<P extends keyof this['__properties__']>(propertyName: P, observer: PropertyObserver<this[P]>) {
unobserve<P extends keyof this>(propertyName: P, observer: PropertyObserver<this[P]>) {
removeObserver(this, propertyName, observer);
}

Expand Down
41 changes: 24 additions & 17 deletions src/JSX.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,17 @@ export type GetCustomElementsProps<T extends keyof HTMLTagNameMap> = Exclude<{
never;
}[keyof JSXInternal.CustomElements], never>;

/**
* Get HTML attributes by prototype.
*/
type ElementAttributes<T extends Element> = {
[K in keyof HTMLTagNameMap]: HTMLTagNameMap[K] extends T ? IntrinsicElementAttributes[K] : HTMLAttributes;
}[keyof HTMLTagNameMap];

/**
* Get render attributes set.
*/
export type AttributeProperties<T> = Omit<T, 'style' | 'class'>;
export type AttributeProperties<T, A> = T & Omit<A, 'style' | 'class' | keyof T>;

/**
* Get render properties for keyed nodes.
Expand Down Expand Up @@ -97,7 +104,7 @@ export type VElement<T extends Element> = {
type: T;
key: unknown;
namespace: string;
properties: Props<T> & AttributeProperties<HTMLAttributes> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
properties: AttributeProperties<Props<T>, ElementAttributes<T>> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
children: Template[];
[V_SYM]: true;
};
Expand All @@ -109,7 +116,7 @@ export type VComponent<T extends ComponentConstructor> = {
type: T;
key?: unknown;
namespace?: string;
properties: Props<InstanceType<T>> & AttributeProperties<HTMLAttributes> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
properties: AttributeProperties<Props<InstanceType<T>>, HTMLAttributes> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
children: Template[];
[V_SYM]: true;
};
Expand All @@ -120,7 +127,7 @@ export type VComponent<T extends ComponentConstructor> = {
export type VSlot = {
type: 'slot';
key: unknown;
properties: AttributeProperties<IntrinsicElementAttributes['slot']> & KeyedProperties & TreeProperties & EventProperties;
properties: AttributeProperties<Props<HTMLSlotElement>, IntrinsicElementAttributes['slot']> & KeyedProperties & TreeProperties & EventProperties;
children: Template[];
[V_SYM]: true;
};
Expand All @@ -132,7 +139,7 @@ export type VTag<T extends keyof HTMLTagNameMap | keyof SVGTagNameMap> = {
type: T;
key: unknown;
namespace: string;
properties: AttributeProperties<IntrinsicElementAttributes[T]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
properties: AttributeProperties<T extends keyof HTMLTagNameMap ? Props<HTMLTagNameMap[T]> : T extends keyof SVGTagNameMap ? Props<SVGTagNameMap[T]> : Props<HTMLElement>, IntrinsicElementAttributes[T]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
children: Template[];
[V_SYM]: true;
};
Expand Down Expand Up @@ -221,10 +228,10 @@ export const isVTag = (target: VObject): target is VTag<keyof HTMLTagNameMap | k

function h(tagOrComponent: typeof Fragment, properties?: null, ...children: Template[]): VFragment;
function h<T extends FunctionComponent>(tagOrComponent: T, properties: Parameters<T>[0] & KeyedProperties & TreeProperties, ...children: Template[]): VFunction<T>;
function h<T extends ComponentConstructor>(tagOrComponent: T, properties: Props<InstanceType<T>> & HTMLAttributes & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VComponent<T>;
function h<T extends Element>(tagOrComponent: T, properties: Props<T> & HTMLAttributes & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VElement<T>;
function h<T extends keyof HTMLTagNameMap>(tagOrComponent: T, properties: Props<T> & IntrinsicElementAttributes[T] & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VTag<T>;
function h<T extends keyof SVGTagNameMap>(tagOrComponent: T, properties: Props<T> & IntrinsicElementAttributes[T] & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VTag<T>;
function h<T extends ComponentConstructor>(tagOrComponent: T, properties: AttributeProperties<Props<InstanceType<T>>, HTMLAttributes> & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VComponent<T>;
function h<T extends Element>(tagOrComponent: T, properties: AttributeProperties<Props<T>, ElementAttributes<T>> & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VElement<T>;
function h<T extends keyof SVGTagNameMap>(tagOrComponent: T, properties: AttributeProperties<Props<SVGTagNameMap[T]>, IntrinsicElementAttributes[T]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VTag<T>;
function h<T extends keyof HTMLTagNameMap>(tagOrComponent: T, properties: AttributeProperties<Props<HTMLTagNameMap[T]>, IntrinsicElementAttributes[T]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties, ...children: Template[]): VTag<T>;
/**
* Function factory to use as JSX pragma.
*
Expand All @@ -235,7 +242,7 @@ function h<T extends keyof SVGTagNameMap>(tagOrComponent: T, properties: Props<T
*/
function h<T extends typeof Fragment | FunctionComponent | ComponentConstructor | Element | keyof HTMLTagNameMap | keyof SVGTagNameMap>(
tagOrComponent: T,
properties: HTMLAttributes & KeyedProperties & TreeProperties & ElementProperties | null = null,
properties: AttributeProperties<Props<HTMLElement>, HTMLAttributes> & KeyedProperties & TreeProperties & ElementProperties | null = null,
...children: Template[]
) {
const { children: propertiesChildren } = (properties || {}) as TreeProperties;
Expand Down Expand Up @@ -283,10 +290,10 @@ function h<T extends typeof Fragment | FunctionComponent | ComponentConstructor
}

function jsx<T extends FunctionComponent>(tagOrComponent: T, properties: Parameters<T>[0] & TreeProperties, key?: unknown): VFunction<T>;
function jsx<T extends ComponentConstructor>(tagOrComponent: T, properties: Props<InstanceType<T>> & HTMLAttributes & TreeProperties & EventProperties & ElementProperties, key?: unknown): VComponent<T>;
function jsx<T extends Element>(tagOrComponent: T, properties: Props<T> & HTMLAttributes & TreeProperties & EventProperties & ElementProperties, key?: unknown): VElement<T>;
function jsx<T extends keyof HTMLTagNameMap>(tagOrComponent: T, properties: Props<T> & IntrinsicElementAttributes[T] & TreeProperties & EventProperties & ElementProperties, key?: unknown): VTag<T>;
function jsx<T extends keyof SVGTagNameMap>(tagOrComponent: T, properties: Props<T> & IntrinsicElementAttributes[T] & TreeProperties & EventProperties & ElementProperties, key?: unknown): VTag<T>;
function jsx<T extends ComponentConstructor>(tagOrComponent: T, properties: AttributeProperties<Props<InstanceType<T>>, HTMLAttributes> & TreeProperties & EventProperties & ElementProperties, key?: unknown): VComponent<T>;
function jsx<T extends Element>(tagOrComponent: T, properties: AttributeProperties<Props<T>, ElementAttributes<T>> & TreeProperties & EventProperties & ElementProperties, key?: unknown): VElement<T>;
function jsx<T extends keyof SVGTagNameMap>(tagOrComponent: T, properties: AttributeProperties<Props<SVGTagNameMap[T]>, IntrinsicElementAttributes[T]> & TreeProperties & EventProperties & ElementProperties, key?: unknown): VTag<T>;
function jsx<T extends keyof HTMLTagNameMap>(tagOrComponent: T, properties: AttributeProperties<Props<HTMLTagNameMap[T]>, IntrinsicElementAttributes[T]> & TreeProperties & EventProperties & ElementProperties, key?: unknown): VTag<T>;
/**
* Function factory to use as JSX pragma.
*
Expand Down Expand Up @@ -330,11 +337,11 @@ export namespace JSXInternal {
[K in keyof CustomElements]:
'extends' extends keyof JSXInternal.CustomElements[K] ?
never :
Props<CustomElements[K]> & AttributeProperties<HTMLAttributes> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
AttributeProperties<Props<CustomElements[K]>, HTMLAttributes> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
} & {
[K in keyof HTMLTagNameMap]: (({ is?: never } & Props<HTMLTagNameMap[K]>) | GetCustomElementsProps<K>) & AttributeProperties<IntrinsicElementAttributes[K]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
[K in keyof HTMLTagNameMap]: AttributeProperties<(({ is?: never } & Props<HTMLTagNameMap[K]>) | GetCustomElementsProps<K>), IntrinsicElementAttributes[K]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
} & {
[K in keyof SVGTagNameMap]: Props<SVGTagNameMap[K]> & AttributeProperties<IntrinsicElementAttributes[K]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
[K in keyof SVGTagNameMap]: AttributeProperties<Props<SVGTagNameMap[K]>, IntrinsicElementAttributes[K]> & KeyedProperties & TreeProperties & EventProperties & ElementProperties;
};
}

Expand Down
6 changes: 3 additions & 3 deletions src/events.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type ComponentInstance, type ComponentConstructor } from './Component';
import { type MethodsOf } from './property';
import { type Methods } from './property';
import { type Constructor, type ClassElement, HTMLElementConstructor, isElement, isEvent, matchesImpl, createEventImpl, hasOwnProperty, getOwnPropertyDescriptor, getPrototypeOf } from './helpers';

/**
Expand Down Expand Up @@ -452,7 +452,7 @@ export const defineListeners = <T extends ComponentInstance>(prototype: T) => {
* @param methodKey The method name.
* @returns The property descriptor.
*/
export const createListener = <T extends ComponentInstance, P extends MethodsOf<T>>(
export const createListener = <T extends ComponentInstance, P extends keyof Methods<T>>(
targetOrClassElement: T,
eventName: string,
target: EventTarget | null,
Expand Down Expand Up @@ -492,7 +492,7 @@ function listen(eventName: string, target: EventTarget, options?: AddEventListen
* @returns The decorator initializer.
*/
function listen(eventName: string, target?: string | EventTarget | AddEventListenerOptions, options?: AddEventListenerOptions) {
return <T extends ComponentInstance, P extends MethodsOf<T>>(
return <T extends ComponentInstance, P extends keyof Methods<T>>(
targetOrClassElement: T,
methodKey: P
) => createListener(
Expand Down
Loading

0 comments on commit a4c6d61

Please sign in to comment.