From 229e28706ec8da157e56d24d6cc20bc10f1a8ea4 Mon Sep 17 00:00:00 2001 From: Trygve Wastvedt Date: Tue, 8 May 2018 12:12:01 -0500 Subject: [PATCH] A-Frame additions (#25006) * Add new PropertyTypes * A-Frame: Expand registerComponent test. * Add generics to properties, components, and systems. * Add missing ShaderDefinition interface. * Add missing event data. * Add missing throttle and throttleTick functions. * Update Typescript version * Use classes for component, system, and geometry * Add tests for class inheritance. * Improve defaults, rename ComponentBase -> ComponentDefault * Saw the sign - many simplifications, return to interfaces Can't extend a class definition that doesn't exist at runtime, so we need to use interfaces? * Remove unnecessary generics * Simplified some references, added a couple tests. * Moving undefined system from generic to property. * Revert "Update Typescript version" This reverts commit 43ef72cef75b0bcee2d04eddcaa0f594290ec46f. --- types/aframe/aframe-tests.ts | 73 +++++++++++++-- types/aframe/index.d.ts | 171 +++++++++++++++++++---------------- types/aframe/tslint.json | 1 - 3 files changed, 160 insertions(+), 85 deletions(-) diff --git a/types/aframe/aframe-tests.ts b/types/aframe/aframe-tests.ts index 5af66a09d1..5e2bd23e36 100644 --- a/types/aframe/aframe-tests.ts +++ b/types/aframe/aframe-tests.ts @@ -21,9 +21,9 @@ type MyEntity = AFrame.Entity<{ material: THREE.Material; sound: { pause(): void }; }>; -const camera = document.querySelector('a-entity[camera]').components.camera; -const material = document.querySelector('a-entity[material]').components.material; -document.querySelector('a-entity[sound]').components.sound.pause(); +const camera = (document.querySelector('a-entity[camera]') as MyEntity).components.camera; +const material = (document.querySelector('a-entity[material]') as MyEntity).components.material; +(document.querySelector('a-entity[sound]') as MyEntity).components.sound.pause(); entity.getDOMAttribute('geometry').primitive; @@ -38,21 +38,82 @@ entity.addEventListener('child-detached', (event) => { }); // Components -const Component = AFRAME.registerComponent('test', {}); + +interface TestComponent extends AFrame.Component { + multiply: (f: number) => number; + + data: { + myProperty: any[], + string: string, + num: number + }; + + system: TestSystem; +} + +const Component = AFRAME.registerComponent('test-component', { + schema: { + myProperty: { + default: [], + parse() { return [true]; }, + }, + string: { type: 'string' }, + num: 0 + }, + init() { + this.data.num = 0; + }, + update() {}, + tick() {}, + remove() {}, + pause() {}, + play() {}, + + multiply(this: TestComponent, f: number) { + // Reference to system because both were registered with the same name. + return f * this.data.num * this.system.data.counter; + } +}); // Scene const scene = document.querySelector('a-scene'); scene.hasLoaded; // System -const system = scene.systems['systemName']; + +interface TestSystem extends AFrame.System { + data: { + counter: number; + }; +} + +const testSystem: AFrame.SystemDefinition = { + schema: { + counter: 0 + }, + + init() { + this.data.counter = 1; + } +}; + +AFRAME.registerSystem('test-component', testSystem); // Register Custom Geometry -AFRAME.registerGeometry('a-test-geometry', { + +interface TestGeometry extends AFrame.Geometry { + schema: AFrame.MultiPropertySchema<{ + groupIndex: number; + }>; +} + +AFRAME.registerGeometry('a-test-geometry', { schema: { groupIndex: { default: 0 } }, init(data) { this.geometry = new THREE.Geometry(); + const temp = data.groupIndex; + temp; } }); diff --git a/types/aframe/index.d.ts b/types/aframe/index.d.ts index 0da1ed0ef5..b405de0273 100644 --- a/types/aframe/index.d.ts +++ b/types/aframe/index.d.ts @@ -2,6 +2,7 @@ // Project: https://aframe.io/ // Definitions by: Paul Shannon // Roberto Ritger +// Trygve Wastvedt // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.3 @@ -19,7 +20,7 @@ declare var hasNativeWebVRImplementation: boolean; interface Document { createElement(tagName: string): AFrame.Entity; querySelector(selectors: 'a-scene'): AFrame.Scene; - querySelector>(selectors: string): T; + querySelector(selectors: string): AFrame.Entity; querySelectorAll(selectors: string): NodeListOf | Element>; } @@ -36,15 +37,15 @@ declare namespace AFrame { components: { [ key: string ]: ComponentDescriptor }; geometries: { [ key: string ]: GeometryDescriptor }; primitives: { [ key: string ]: Entity }; - registerComponent(name: string, component: ComponentDefinition): ComponentConstructor; + registerComponent(name: string, component: ComponentDefinition): ComponentConstructor; registerElement(name: string, element: ANode): void; - registerGeometry(name: string, geometry: GeometryDefinition): Geometry; + registerGeometry(name: string, geometry: GeometryDefinition): GeometryConstructor; registerPrimitive(name: string, primitive: PrimitiveDefinition): void; - registerShader(name: string, shader: any): void; - registerSystem(name: string, definition: SystemDefinition): void; + registerShader(name: string, shader: T): ShaderConstructor; + registerSystem(name: string, definition: SystemDefinition): SystemConstructor; schema: SchemaUtils; shaders: { [ key: string ]: ShaderDescriptor }; - systems: { [key: string]: System }; + systems: { [key: string]: SystemConstructor }; THREE: typeof THREE; TWEEN: typeof TWEEN; utils: Utils; @@ -89,54 +90,39 @@ declare namespace AFrame { tick(): void; } - interface Component { + interface Component { attrName?: string; - data?: any; + data: T; dependencies?: string[]; el: Entity; id: string; multiple?: boolean; name: string; - schema: Schema; + schema: Schema; + system: S | undefined; - init(data?: any): void; - pause(): void; - play(): void; - remove(): void; - tick?(time: number, timeDelta: number): void; - update(oldData: any): void; - updateSchema?(): void; + init(this: this, data?: T): void; + pause(this: this): void; + play(this: this): void; + remove(this: this): void; + tick?(this: this, time: number, timeDelta: number): void; + update(this: this, oldData: T): void; + updateSchema?(this: this): void; - extendSchema(update: Schema): void; - flushToDOM(): void; + extendSchema(this: this, update: Schema): void; + flushToDOM(this: this): void; } - interface ComponentConstructor { - new (el: Entity, name: string, id: string): Component; + interface ComponentConstructor { + new (el: Entity, attrValue: string, id: string): T; } - interface ComponentDefinition { - dependencies?: string[]; - el?: Entity; - id?: string; - multiple?: boolean; - schema?: Schema; + type ComponentDefinition = Partial; - init?(data?: any): void; - pause?(): void; - play?(): void; - remove?(): void; - tick?(time: number, timeDelta: number): void; - update?(oldData: any): void; - updateSchema?(): void; - - [ key: string ]: any; - } - - interface ComponentDescriptor { - Component: Component; - dependencies: string[] | null; - multiple: boolean | null; + interface ComponentDescriptor { + Component: ComponentConstructor; + dependencies: string[] | undefined; + multiple: boolean | undefined; // internal APIs2 // parse @@ -144,7 +130,6 @@ declare namespace AFrame { // schema // stringify // type - [ key: string ]: any; } interface Coordinate { @@ -153,8 +138,14 @@ declare namespace AFrame { z: number; } + interface DefaultComponents { + position: Component; + rotation: Component; + scale: Component; + } + interface Entity> extends ANode { - components: C; + components: C & DefaultComponents; isPlaying: boolean; object3D: THREE.Object3D; object3DMap: ObjectMap; @@ -165,8 +156,8 @@ declare namespace AFrame { /** * @deprecated since 0.4.0 */ - getComputedAttribute(attr: string): T; - getDOMAttribute(attr: string): T; + getComputedAttribute(attr: string): Component; + getDOMAttribute(attr: string): any; getObject3D(type: string): THREE.Object3D; getOrCreateObject3D(type: string, construct: any): THREE.Object3D; is(stateName: string): boolean; @@ -179,7 +170,6 @@ declare namespace AFrame { // getAttribute specific usages getAttribute(type: string): any; - getAttribute(attr: string): T; getAttribute(type: 'position' | 'rotation' | 'scale'): Coordinate; // setAttribute specific usages @@ -192,12 +182,18 @@ declare namespace AFrame { addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void; } - type DetailEvent = Event & { detail: D }; + type DetailEvent = Event & { + detail: D; + target: EventTarget & Entity; + }; interface EntityEventMap { 'child-attached': DetailEvent<{ el: Element | Entity }>; 'child-detached': DetailEvent<{ el: Element | Entity }>; - 'componentchanged': DetailEvent<{ name: string }>; + 'componentchanged': DetailEvent<{ + name: string, + id: string + }>; 'componentremoved': DetailEvent<{ name: string, id: string, @@ -215,23 +211,28 @@ declare namespace AFrame { interface Geometry { name: string; geometry: THREE.Geometry; - schema: Schema; - update(data: object): void; - [ key: string ]: any; + schema: Schema; + + init(this: this, data: { [P in keyof this['schema']]: any }): void; + // Would like the above to be: + // init?(this: this, data?: { [P in keyof T['schema']]: T['schema'][P]['default'] } ): void; + // I think this is prevented by the following issue: https://github.com/Microsoft/TypeScript/issues/21760. } - interface GeometryDefinition extends ComponentDefinition { - geometry?: THREE.Geometry; + interface GeometryConstructor { + new (): T; } - interface GeometryDescriptor { - Geometry: Geometry; + type GeometryDefinition = Partial; + + interface GeometryDescriptor { + Geometry: GeometryConstructor; schema: Schema; } - interface MultiPropertySchema { - [ key: string ]: SinglePropertySchema; - } + type MultiPropertySchema = { + [P in keyof T]: SinglePropertySchema | T[P]; + }; interface PrimitiveDefinition { defaultComponents?: any; // TODO cleanup type @@ -240,8 +241,9 @@ declare namespace AFrame { transforms?: any; // TODO cleanup type } - type PropertyTypes = 'array' | 'boolean' | 'color' | 'int' | 'number' | 'selector' | - 'selectorAll' | 'src' | 'string' | 'vec2' | 'vec3' | 'vec4'; + type PropertyTypes = 'array' | 'asset' | 'audio' | 'boolean' | 'color' | + 'int' | 'map' | 'model' | 'number' | 'selector' | 'selectorAll' | + 'string' | 'vec2' | 'vec3' | 'vec4'; type SceneEvents = 'enter-vr' | 'exit-vr' | 'loaded' | 'renderstart'; @@ -265,7 +267,7 @@ declare namespace AFrame { addEventListener(type: SceneEvents, listener: EventListener, useCapture?: boolean): void; } - type Schema = SinglePropertySchema | MultiPropertySchema; + type Schema = SinglePropertySchema | MultiPropertySchema; interface SchemaUtils { isSingleProperty(schema: Schema): boolean; @@ -274,11 +276,25 @@ declare namespace AFrame { interface Shader { name: string; - schema: Schema; + data: { [key: string]: any }; + schema: Schema; + material: THREE.Material; + vertexShader: string; + fragmentShader: string; + + init(this: this, data?: this['data']): void; + tick?(this: this, time: number, timeDelta: number): void; + update(this: this, oldData: this['data']): void; } - interface ShaderDescriptor { - Shader: Shader; + interface ShaderConstructor { + new (): T; + } + + type ShaderDefinition = Partial; + + interface ShaderDescriptor { + Shader: ShaderConstructor; schema: Schema; } @@ -287,27 +303,23 @@ declare namespace AFrame { 'default'?: T; parse?(value: string): T; stringify?(value: T): string; - [ key: string ]: any; } interface System { - data: any; - schema: Schema; - init(): void; - pause(): void; - play(): void; - tick?(): void; + data: { [key: string]: any }; + schema: Schema; + init(this: this): void; + pause(this: this): void; + play(this: this): void; + tick?(this: this, t: number, dt: number): void; } - interface SystemDefinition { - schema?: Schema; - init?(): void; - pause?(): void; - play?(): void; - tick?(): void; - [ key: string ]: any; + interface SystemConstructor { + new (scene: Scene): T; } + type SystemDefinition = Partial; + interface Utils { coordinates: { isCoordinate(value: string): boolean; @@ -326,5 +338,8 @@ declare namespace AFrame { diff(a: object, b: object): object; extend(target: object, ... source: object[]): object; extendDeep(target: object, ... source: object[]): object; + + throttle(tickFunction: () => void, minimumInterval: number, optionalContext?: {}): (t: number, dt: number) => void; + throttleTick(tickFunction: (t: number, dt: number) => void, minimumInterval: number, optionalContext?: {}): (t: number, dt: number) => void; } } diff --git a/types/aframe/tslint.json b/types/aframe/tslint.json index 71ee04c4e1..495d29983d 100644 --- a/types/aframe/tslint.json +++ b/types/aframe/tslint.json @@ -1,6 +1,5 @@ { "extends": "dtslint/dt.json", "rules": { - "no-unnecessary-generics": false } }