Skip to content

Commit 962f74d

Browse files
Jérémy MelchorJérémy Melchor
authored andcommitted
Better types inferences for Rect attributes
1 parent ee8a5e8 commit 962f74d

File tree

8 files changed

+27
-21
lines changed

8 files changed

+27
-21
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ types
2020
out.png
2121
cmj
2222
.test-temp
23+
.history
2324

2425
# Numerous always-ignore extensions
2526
*.diff

src/Container.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ export interface ContainerConfig extends NodeConfig {
3232
*/
3333
export abstract class Container<
3434
ChildType extends Node = Node,
35-
> extends Node<ContainerConfig> {
35+
Config extends ContainerConfig = ContainerConfig
36+
> extends Node<Config> {
3637
children: Array<ChildType> = [];
3738

3839
/**

src/Node.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { Layer } from './Layer.ts';
1010
import type { Shape } from './Shape.ts';
1111
import type { Stage } from './Stage.ts';
1212
import type { GetSet, IRect, Vector2d } from './types.ts';
13-
import { Transform, Util } from './Util.ts';
13+
import { Transform, Util, type AnyString } from './Util.ts';
1414
import {
1515
getBooleanValidator,
1616
getNumberValidator,
@@ -134,9 +134,8 @@ type globalCompositeOperationType =
134134
| 'color'
135135
| 'luminosity';
136136

137-
export interface NodeConfig {
138-
// allow any custom attribute
139-
[index: string]: any;
137+
// allow any custom attribute
138+
export type NodeConfig<Props extends Record<string, any> = {}> = Props & {
140139
x?: number;
141140
y?: number;
142141
width?: number;
@@ -1015,13 +1014,13 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
10151014
* @example
10161015
* var x = node.getAttr('x');
10171016
*/
1018-
getAttr<T>(attr: string) {
1019-
const method = 'get' + Util._capitalize(attr);
1017+
getAttr<AttrConfig extends Config, K extends AnyString<keyof Config>>(attr: K): K extends keyof AttrConfig ? AttrConfig[K] : any {
1018+
const method = 'get' + Util._capitalize(attr as string);
10201019
if (Util._isFunction((this as any)[method])) {
10211020
return (this as any)[method]();
10221021
}
10231022
// otherwise get directly
1024-
return this.attrs[attr] as T | undefined;
1023+
return this.attrs[attr];
10251024
}
10261025
/**
10271026
* get ancestors
@@ -1050,8 +1049,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
10501049
* @name Konva.Node#getAttrs
10511050
* @returns {Object}
10521051
*/
1053-
getAttrs() {
1054-
return (this.attrs || {}) as Config & Record<string, any>;
1052+
getAttrs(): Config {
1053+
return (this.attrs || {});
10551054
}
10561055
/**
10571056
* set multiple attrs at once using an object literal
@@ -1065,7 +1064,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
10651064
* fill: 'red'
10661065
* });
10671066
*/
1068-
setAttrs(config: any) {
1067+
setAttrs(config?: Config) {
10691068
this._batchTransformChanges(() => {
10701069
let key, method;
10711070
if (!config) {
@@ -1624,7 +1623,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
16241623
* @returns {Object}
16251624
*/
16261625
toObject() {
1627-
let attrs = this.getAttrs() as any,
1626+
let attrs = this.getAttrs(),
16281627
key,
16291628
val,
16301629
getter,
@@ -2405,8 +2404,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
24052404
* @example
24062405
* node.setAttr('x', 5);
24072406
*/
2408-
setAttr(attr: string, val) {
2409-
const func = this[SET + Util._capitalize(attr)];
2407+
setAttr<AttrConfig extends Config, K extends AnyString<keyof Config>>(attr: K, val: K extends keyof AttrConfig ? AttrConfig[K] : any) {
2408+
const func = this[SET + Util._capitalize(attr as string)];
24102409

24112410
if (Util._isFunction(func)) {
24122411
func.call(this, val);
@@ -2422,7 +2421,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
24222421
drawNode?.batchDraw();
24232422
}
24242423
}
2425-
_setAttr(key: string, val) {
2424+
_setAttr<AttrConfig extends Config, K extends AnyString<keyof Config>>(key: K, val: K extends keyof AttrConfig ? AttrConfig[K] : any) {
24262425
const oldVal = this.attrs[key];
24272426
if (oldVal === val && !Util.isObject(val)) {
24282427
return;
@@ -2878,7 +2877,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
28782877
}
28792878
}
28802879

2881-
interface AnimTo extends NodeConfig {
2880+
interface AnimTo extends NodeConfig<Record<string, any>> {
28822881
onFinish?: Function;
28832882
onUpdate?: Function;
28842883
duration?: number;

src/Shape.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export type ShapeConfigHandler<TTarget> = {
2626
export type LineJoin = 'round' | 'bevel' | 'miter';
2727
export type LineCap = 'butt' | 'round' | 'square';
2828

29-
export interface ShapeConfig extends NodeConfig {
29+
export type ShapeConfig<Props extends Record<string, any> = {}> = NodeConfig<Props> & {
3030
fill?: string | CanvasGradient;
3131
fillPatternImage?: HTMLImageElement;
3232
fillPatternX?: number;

src/Stage.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ export const stages: Stage[] = [];
154154
* });
155155
*/
156156

157-
export class Stage extends Container<Layer> {
157+
export class Stage extends Container<Layer, StageConfig> {
158158
content: HTMLDivElement;
159159
pointerPos: Vector2d | null;
160160
_pointerPositions: (Vector2d & { id?: number })[] = [];

src/Tween.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ class TweenEngine {
151151
}
152152

153153
export interface TweenConfig extends NodeConfig {
154+
easing?: typeof Easings[keyof typeof Easings];
155+
yoyo?: boolean;
156+
onReset?: Function;
154157
onFinish?: Function;
155158
onUpdate?: Function;
156159
duration?: number;
@@ -419,7 +422,7 @@ export class Tween {
419422
// after tweening points of line we need to set original end
420423
const attrs = Tween.attrs[node._id][this._id];
421424
if (attrs.points && attrs.points.trueEnd) {
422-
node.setAttr('points', attrs.points.trueEnd);
425+
node.setAttr('points' as any, attrs.points.trueEnd);
423426
}
424427

425428
if (this.onFinish) {

src/Util.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,3 +1121,5 @@ export const Util = {
11211121
}
11221122
},
11231123
};
1124+
1125+
export type AnyString<T> = T | (string & {})

src/shapes/Rect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { GetSet } from '../types.ts';
88
import type { Context } from '../Context.ts';
99
import { getNumberOrArrayOfNumbersValidator } from '../Validators.ts';
1010

11-
export interface RectConfig extends ShapeConfig {
11+
export type RectConfig<Props extends Record<string, any> = {}> = ShapeConfig<Props> & {
1212
cornerRadius?: number | number[];
1313
}
1414

@@ -30,7 +30,7 @@ export interface RectConfig extends ShapeConfig {
3030
* strokeWidth: 5
3131
* });
3232
*/
33-
export class Rect extends Shape<RectConfig> {
33+
export class Rect<Props extends Record<string, any> = {}> extends Shape<RectConfig<Props>> {
3434
_sceneFunc(context: Context) {
3535
const cornerRadius = this.cornerRadius(),
3636
width = this.width(),

0 commit comments

Comments
 (0)