From c71ee1de88022ad0f0794533dad7e614e9ea0c14 Mon Sep 17 00:00:00 2001 From: makepost Date: Fri, 23 Mar 2018 18:58:32 +0200 Subject: [PATCH] Decorate: Fix in type-checked JS, resolves #1448 --- src/api/decorate.ts | 4 ++-- src/api/observable.ts | 2 +- test/base/decorate.js | 43 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/api/decorate.ts b/src/api/decorate.ts index c5ccca5aa..9c3b42fc8 100644 --- a/src/api/decorate.ts +++ b/src/api/decorate.ts @@ -2,11 +2,11 @@ import { invariant, isPlainObject } from "../utils/utils" export function decorate( clazz: new (...args: any[]) => T, - decorators: { [P in keyof T]: MethodDecorator | PropertyDecorator } + decorators: { [P in keyof T]?: MethodDecorator | PropertyDecorator } ): void export function decorate( object: T, - decorators: { [P in keyof T]: MethodDecorator | PropertyDecorator } + decorators: { [P in keyof T]?: MethodDecorator | PropertyDecorator } ): T export function decorate(thing: any, decorators: any) { process.env.NODE_ENV !== "production" && diff --git a/src/api/observable.ts b/src/api/observable.ts index d8bf38ead..83610cbdf 100644 --- a/src/api/observable.ts +++ b/src/api/observable.ts @@ -92,7 +92,7 @@ function createObservable(v: any, arg2?: any, arg3?: any) { export interface IObservableFactory { // observable overloads (value: number | string | null | undefined | boolean): never // Nope, not supported, use box - (target: Object, key: string, baseDescriptor?: PropertyDescriptor): any // decorator + (target: Object, key: string | symbol, baseDescriptor?: PropertyDescriptor): any // decorator (value: T[], options?: CreateObservableOptions): IObservableArray (value: Map, options?: CreateObservableOptions): ObservableMap ( diff --git a/test/base/decorate.js b/test/base/decorate.js index da9df1c3d..f620c55f0 100644 --- a/test/base/decorate.js +++ b/test/base/decorate.js @@ -1,3 +1,5 @@ +// @ts-check + import { observable, computed, @@ -17,6 +19,7 @@ import { test("decorate should work", function() { class Box { + // @ts-ignore uninitialized height = 20 sizes = [2] @@ -33,7 +36,9 @@ test("decorate should work", function() { ) } addSize() { + // @ts-ignore this.sizes.push([3]) + // @ts-ignore this.sizes.push([4]) } constructor() { @@ -105,7 +110,9 @@ test("decorate should work with plain object", function() { ) }, addSize() { + // @ts-ignore this.sizes.push([3]) + // @ts-ignore this.sizes.push([4]) } } @@ -171,7 +178,9 @@ test("decorate should work with Object.create", function() { ) }, addSize() { + // @ts-ignore this.sizes.push([3]) + // @ts-ignore this.sizes.push([4]) } } @@ -233,12 +242,16 @@ test("decorate should work with constructor function", function() { configurable: true, enumerable: false, get() { + /** @type {Box} */ + var t /** @type {any} */ = this + return ( - this.undeclared * - this.height * - this.sizes.length * - this.someFunc() * - (this.uninitialized ? 2 : 1) + // @ts-ignore + t.undeclared * + t.height * + t.sizes.length * + t.someFunc() * + (t.uninitialized ? 2 : 1) ) } }) @@ -262,6 +275,7 @@ test("decorate should work with constructor function", function() { } const box = new Box() + // @ts-ignore box.undeclared = 1 expect(isObservableObject(box)).toBe(true) @@ -278,6 +292,7 @@ test("decorate should work with constructor function", function() { var ar = [] autorun(() => { + // @ts-ignore ar.push(box.width) }) @@ -292,11 +307,14 @@ test("decorate should work with constructor function", function() { expect(ar.slice()).toEqual([40, 20, 60, 210, 420]) box.addSize() expect(ar.slice()).toEqual([40, 20, 60, 210, 420, 700]) + // @ts-ignore box.undeclared = 2 expect(ar.slice()).toEqual([40, 20, 60, 210, 420, 700, 1400]) const box2 = new Box() + // @ts-ignore box2.undeclared = 1 + // @ts-ignore expect(box2.width).toBe(40) // no shared state! }) @@ -318,3 +336,18 @@ test("decorate should work with inheritance through Object.create", () => { expect(child2.x).toBe(5) expect(child1.x).toBe(4) }) + +test("decorate should work with ES6 constructor", () => { + class Todo { + constructor() { + this.finished = false + this.id = Math.random() + this.title = "" + } + } + + decorate(Todo, { + finished: observable, + title: observable + }) +})