diff --git a/.gitignore b/.gitignore index b7b7533b..485396e5 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ types out.png cmj .test-temp +.history # Numerous always-ignore extensions *.diff diff --git a/src/Container.ts b/src/Container.ts index 83d42e8b..36d257d9 100644 --- a/src/Container.ts +++ b/src/Container.ts @@ -32,7 +32,8 @@ export interface ContainerConfig extends NodeConfig { */ export abstract class Container< ChildType extends Node = Node, -> extends Node { + Config extends ContainerConfig = ContainerConfig +> extends Node { children: Array = []; /** diff --git a/src/Node.ts b/src/Node.ts index 25f48cf5..7c521cbd 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -10,7 +10,7 @@ import type { Layer } from './Layer.ts'; import type { Shape } from './Shape.ts'; import type { Stage } from './Stage.ts'; import type { GetSet, IRect, Vector2d } from './types.ts'; -import { Transform, Util } from './Util.ts'; +import { Transform, Util, type AnyString } from './Util.ts'; import { getBooleanValidator, getNumberValidator, @@ -134,9 +134,8 @@ type globalCompositeOperationType = | 'color' | 'luminosity'; -export interface NodeConfig { - // allow any custom attribute - [index: string]: any; +// allow any custom attribute +export type NodeConfig = {}> = Props & { x?: number; y?: number; width?: number; @@ -1015,13 +1014,13 @@ export abstract class Node { * @example * var x = node.getAttr('x'); */ - getAttr(attr: string) { - const method = 'get' + Util._capitalize(attr); + getAttr>(attr: K): K extends keyof AttrConfig ? AttrConfig[K] : any { + const method = 'get' + Util._capitalize(attr as string); if (Util._isFunction((this as any)[method])) { return (this as any)[method](); } // otherwise get directly - return this.attrs[attr] as T | undefined; + return this.attrs[attr]; } /** * get ancestors @@ -1050,8 +1049,8 @@ export abstract class Node { * @name Konva.Node#getAttrs * @returns {Object} */ - getAttrs() { - return (this.attrs || {}) as Config & Record; + getAttrs(): Config { + return (this.attrs || {}); } /** * set multiple attrs at once using an object literal @@ -1065,7 +1064,7 @@ export abstract class Node { * fill: 'red' * }); */ - setAttrs(config: any) { + setAttrs(config?: Config) { this._batchTransformChanges(() => { let key, method; if (!config) { @@ -1624,7 +1623,7 @@ export abstract class Node { * @returns {Object} */ toObject() { - let attrs = this.getAttrs() as any, + let attrs = this.getAttrs(), key, val, getter, @@ -2405,8 +2404,8 @@ export abstract class Node { * @example * node.setAttr('x', 5); */ - setAttr(attr: string, val) { - const func = this[SET + Util._capitalize(attr)]; + setAttr>(attr: K, val: K extends keyof AttrConfig ? AttrConfig[K] : any) { + const func = this[SET + Util._capitalize(attr as string)]; if (Util._isFunction(func)) { func.call(this, val); @@ -2422,7 +2421,7 @@ export abstract class Node { drawNode?.batchDraw(); } } - _setAttr(key: string, val) { + _setAttr>(key: K, val: K extends keyof AttrConfig ? AttrConfig[K] : any) { const oldVal = this.attrs[key]; if (oldVal === val && !Util.isObject(val)) { return; @@ -2878,7 +2877,7 @@ export abstract class Node { } } -interface AnimTo extends NodeConfig { +interface AnimTo extends NodeConfig> { onFinish?: Function; onUpdate?: Function; duration?: number; diff --git a/src/Shape.ts b/src/Shape.ts index aeb6fa4f..b300a642 100644 --- a/src/Shape.ts +++ b/src/Shape.ts @@ -26,7 +26,7 @@ export type ShapeConfigHandler = { export type LineJoin = 'round' | 'bevel' | 'miter'; export type LineCap = 'butt' | 'round' | 'square'; -export interface ShapeConfig extends NodeConfig { +export type ShapeConfig = {}> = NodeConfig & { fill?: string | CanvasGradient; fillPatternImage?: HTMLImageElement; fillPatternX?: number; diff --git a/src/Stage.ts b/src/Stage.ts index 36893b87..9ba1d87e 100644 --- a/src/Stage.ts +++ b/src/Stage.ts @@ -154,7 +154,7 @@ export const stages: Stage[] = []; * }); */ -export class Stage extends Container { +export class Stage extends Container { content: HTMLDivElement; pointerPos: Vector2d | null; _pointerPositions: (Vector2d & { id?: number })[] = []; diff --git a/src/Tween.ts b/src/Tween.ts index 7c78011b..ef7c2562 100644 --- a/src/Tween.ts +++ b/src/Tween.ts @@ -151,6 +151,9 @@ class TweenEngine { } export interface TweenConfig extends NodeConfig { + easing?: typeof Easings[keyof typeof Easings]; + yoyo?: boolean; + onReset?: Function; onFinish?: Function; onUpdate?: Function; duration?: number; @@ -419,7 +422,7 @@ export class Tween { // after tweening points of line we need to set original end const attrs = Tween.attrs[node._id][this._id]; if (attrs.points && attrs.points.trueEnd) { - node.setAttr('points', attrs.points.trueEnd); + node.setAttr('points' as any, attrs.points.trueEnd); } if (this.onFinish) { diff --git a/src/Util.ts b/src/Util.ts index 372d3ad2..ea59767a 100644 --- a/src/Util.ts +++ b/src/Util.ts @@ -1121,3 +1121,5 @@ export const Util = { } }, }; + +export type AnyString = T | (string & {}) diff --git a/src/shapes/Rect.ts b/src/shapes/Rect.ts index 581f98c9..be169509 100644 --- a/src/shapes/Rect.ts +++ b/src/shapes/Rect.ts @@ -8,7 +8,7 @@ import type { GetSet } from '../types.ts'; import type { Context } from '../Context.ts'; import { getNumberOrArrayOfNumbersValidator } from '../Validators.ts'; -export interface RectConfig extends ShapeConfig { +export type RectConfig = {}> = ShapeConfig & { cornerRadius?: number | number[]; } @@ -30,7 +30,7 @@ export interface RectConfig extends ShapeConfig { * strokeWidth: 5 * }); */ -export class Rect extends Shape { +export class Rect = {}> extends Shape> { _sceneFunc(context: Context) { const cornerRadius = this.cornerRadius(), width = this.width(),