From 59f7428fa82d6ef511ebd732366459b900b0d88a Mon Sep 17 00:00:00 2001 From: Peter Burns Date: Thu, 18 Apr 2019 14:46:34 -0700 Subject: [PATCH 1/4] Add ugly type assertions for `this` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because of https://github.com/google/closure-compiler/issues/3340 – `this` has an unknown type to closure compiler in static methods. In order to be compatible with the Closure Compiler + JSConformance `BanUnknownThis` check, we must explicitly add type annotations wherever we access `this` in a static method. Yes, this is pretty awful from a legibility perspective. We could improve legibility at the cost of additional size by doing: ```typescript const self = this as typeof LitElement; ``` I went with the zero-size-cost option here. --- src/lib/decorators.ts | 4 +-- src/lib/updating-element.ts | 60 +++++++++++++++++++++---------------- src/lit-element.ts | 12 ++++---- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/lib/decorators.ts b/src/lib/decorators.ts index 43e8db9b..4a5dc5a0 100644 --- a/src/lib/decorators.ts +++ b/src/lib/decorators.ts @@ -106,9 +106,9 @@ const standardProperty = // } // ], // tslint:disable-next-line:no-any decorator - initializer(this: any) { + initializer(this: {[key: string]: unknown}) { if (typeof element.initializer === 'function') { - this[element.key] = element.initializer.call(this); + this[element.key as string] = element.initializer.call(this); } }, finisher(clazz: typeof UpdatingElement) { diff --git a/src/lib/updating-element.ts b/src/lib/updating-element.ts index 1609e854..64d1180c 100644 --- a/src/lib/updating-element.ts +++ b/src/lib/updating-element.ts @@ -233,14 +233,15 @@ export abstract class UpdatingElement extends HTMLElement { */ static get observedAttributes() { // note: piggy backing on this to ensure we're finalized. - this.finalize(); + (this as typeof UpdatingElement).finalize(); const attributes: string[] = []; // Use forEach so this works even if for/of loops are compiled to for loops // expecting arrays - this._classProperties!.forEach((v, p) => { - const attr = this._attributeNameForProperty(p, v); + (this as typeof UpdatingElement)._classProperties!.forEach((v, p) => { + const attr = + (this as typeof UpdatingElement)._attributeNameForProperty(p, v); if (attr !== undefined) { - this._attributeToPropertyMap.set(attr, p); + (this as typeof UpdatingElement)._attributeToPropertyMap.set(attr, p); attributes.push(attr); } }); @@ -255,16 +256,18 @@ export abstract class UpdatingElement extends HTMLElement { /** @nocollapse */ private static _ensureClassProperties() { // ensure private storage for property declarations. - if (!this.hasOwnProperty( - JSCompiler_renameProperty('_classProperties', this))) { - this._classProperties = new Map(); + if (!(this as typeof UpdatingElement) + .hasOwnProperty(JSCompiler_renameProperty( + '_classProperties', (this as typeof UpdatingElement)))) { + (this as typeof UpdatingElement)._classProperties = new Map(); // NOTE: Workaround IE11 not supporting Map constructor argument. const superProperties: PropertyDeclarationMap = - Object.getPrototypeOf(this)._classProperties; + Object.getPrototypeOf((this as typeof UpdatingElement)) + ._classProperties; if (superProperties !== undefined) { superProperties.forEach( (v: PropertyDeclaration, k: PropertyKey) => - this._classProperties!.set(k, v)); + (this as typeof UpdatingElement)._classProperties!.set(k, v)); } } } @@ -282,28 +285,29 @@ export abstract class UpdatingElement extends HTMLElement { // Note, since this can be called by the `@property` decorator which // is called before `finalize`, we ensure storage exists for property // metadata. - this._ensureClassProperties(); - this._classProperties!.set(name, options); + (this as typeof UpdatingElement)._ensureClassProperties(); + (this as typeof UpdatingElement)._classProperties!.set(name, options); // Do not generate an accessor if the prototype already has one, since // it would be lost otherwise and that would never be the user's intention; // Instead, we expect users to call `requestUpdate` themselves from // user-defined accessors. Note that if the super has an accessor we will // still overwrite it - if (options.noAccessor || this.prototype.hasOwnProperty(name)) { + if (options.noAccessor || + (this as typeof UpdatingElement).prototype.hasOwnProperty(name)) { return; } const key = typeof name === 'symbol' ? Symbol() : `__${name}`; - Object.defineProperty(this.prototype, name, { + Object.defineProperty((this as typeof UpdatingElement).prototype, name, { // tslint:disable-next-line:no-any no symbol in index get(): any { - return this[key]; + return (this as {[key: string]: unknown})[key as string]; }, set(this: UpdatingElement, value: unknown) { // tslint:disable-next-line:no-any no symbol in index - const oldValue = (this as any)[name]; + const oldValue = (this as {[key: string]: unknown})[name as string]; // tslint:disable-next-line:no-any no symbol in index - (this as any)[key] = value; - this._requestUpdate(name, oldValue); + (this as {[key: string]: unknown})[key as string] = value; + (this as UpdatingElement)._requestUpdate(name, oldValue); }, configurable: true, enumerable: true @@ -316,25 +320,29 @@ export abstract class UpdatingElement extends HTMLElement { * @nocollapse */ protected static finalize() { - if (this.hasOwnProperty(JSCompiler_renameProperty('finalized', this)) && - this.finalized) { + if ((this as typeof UpdatingElement) + .hasOwnProperty(JSCompiler_renameProperty( + 'finalized', (this as typeof UpdatingElement))) && + (this as typeof UpdatingElement).finalized) { return; } // finalize any superclasses - const superCtor = Object.getPrototypeOf(this); + const superCtor = Object.getPrototypeOf((this as typeof UpdatingElement)); if (typeof superCtor.finalize === 'function') { superCtor.finalize(); } - this.finalized = true; - this._ensureClassProperties(); + (this as typeof UpdatingElement).finalized = true; + (this as typeof UpdatingElement)._ensureClassProperties(); // initialize Map populated in observedAttributes - this._attributeToPropertyMap = new Map(); + (this as typeof UpdatingElement)._attributeToPropertyMap = new Map(); // make any properties // Note, only process "own" properties since this element will inherit // any properties defined on the superClass, and finalization ensures // the entire prototype chain is finalized. - if (this.hasOwnProperty(JSCompiler_renameProperty('properties', this))) { - const props = this.properties; + if ((this as typeof UpdatingElement) + .hasOwnProperty(JSCompiler_renameProperty( + 'properties', (this as typeof UpdatingElement)))) { + const props = (this as typeof UpdatingElement).properties; // support symbols in properties (IE11 does not support this) const propKeys = [ ...Object.getOwnPropertyNames(props), @@ -347,7 +355,7 @@ export abstract class UpdatingElement extends HTMLElement { // note, use of `any` is due to TypeSript lack of support for symbol in // index types // tslint:disable-next-line:no-any no symbol in index - this.createProperty(p, (props as any)[p]); + (this as typeof UpdatingElement).createProperty(p, (props as any)[p]); } } } diff --git a/src/lit-element.ts b/src/lit-element.ts index 194616ca..88f2103f 100644 --- a/src/lit-element.ts +++ b/src/lit-element.ts @@ -88,10 +88,12 @@ export class LitElement extends UpdatingElement { super.finalize(); // Prepare styling that is stamped at first render time. Styling // is built from user provided `styles` or is inherited from the superclass. - this._styles = - this.hasOwnProperty(JSCompiler_renameProperty('styles', this)) ? - this._getUniqueStyles() : - this._styles || []; + (this as typeof LitElement)._styles = + (this as typeof LitElement) + .hasOwnProperty(JSCompiler_renameProperty( + 'styles', (this as typeof LitElement))) ? + (this as typeof LitElement)._getUniqueStyles() : + (this as typeof LitElement)._styles || []; } /** @nocollapse */ @@ -102,7 +104,7 @@ export class LitElement extends UpdatingElement { // shared styles will generate new stylesheet objects, which is wasteful. // This should be addressed when a browser ships constructable // stylesheets. - const userStyles = this.styles; + const userStyles = (this as typeof LitElement).styles; const styles: CSSResult[] = []; if (Array.isArray(userStyles)) { const flatStyles = flattenStyles(userStyles); From 289df3821cbc74c24f181b3c1e6fa5fc1d55fed7 Mon Sep 17 00:00:00 2001 From: Peter Burns Date: Thu, 18 Apr 2019 14:50:11 -0700 Subject: [PATCH 2/4] Remove unnecessary tslint comments. --- src/lib/decorators.ts | 1 - src/lib/updating-element.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/lib/decorators.ts b/src/lib/decorators.ts index 4a5dc5a0..b3b6c383 100644 --- a/src/lib/decorators.ts +++ b/src/lib/decorators.ts @@ -105,7 +105,6 @@ const standardProperty = // initializer: descriptor.initializer, // } // ], - // tslint:disable-next-line:no-any decorator initializer(this: {[key: string]: unknown}) { if (typeof element.initializer === 'function') { this[element.key as string] = element.initializer.call(this); diff --git a/src/lib/updating-element.ts b/src/lib/updating-element.ts index 64d1180c..e09991d8 100644 --- a/src/lib/updating-element.ts +++ b/src/lib/updating-element.ts @@ -303,9 +303,7 @@ export abstract class UpdatingElement extends HTMLElement { return (this as {[key: string]: unknown})[key as string]; }, set(this: UpdatingElement, value: unknown) { - // tslint:disable-next-line:no-any no symbol in index const oldValue = (this as {[key: string]: unknown})[name as string]; - // tslint:disable-next-line:no-any no symbol in index (this as {[key: string]: unknown})[key as string] = value; (this as UpdatingElement)._requestUpdate(name, oldValue); }, From 001f4c3cdf12e2726aaa058adbd3fec219f89ea6 Mon Sep 17 00:00:00 2001 From: Peter Burns Date: Thu, 18 Apr 2019 14:52:41 -0700 Subject: [PATCH 3/4] Format --- src/lib/css-tag.ts | 15 +- src/lib/updating-element.ts | 11 +- src/test/lib/updating-element_test.ts | 409 +++++++++++++------------- src/test/lit-element_test.ts | 70 ++--- 4 files changed, 255 insertions(+), 250 deletions(-) diff --git a/src/lib/css-tag.ts b/src/lib/css-tag.ts index 430d75df..c63ca46b 100644 --- a/src/lib/css-tag.ts +++ b/src/lib/css-tag.ts @@ -60,7 +60,7 @@ export const unsafeCSS = (value: unknown) => { return new CSSResult(String(value), constructionToken); }; -const textFromCSSResult = (value: CSSResult | number) => { +const textFromCSSResult = (value: CSSResult|number) => { if (value instanceof CSSResult) { return value.cssText; } else if (typeof value === 'number') { @@ -79,9 +79,10 @@ const textFromCSSResult = (value: CSSResult | number) => { * used. To incorporate non-literal values `unsafeCSS` may be used inside a * template string part. */ -export const css = (strings: TemplateStringsArray, ...values: (CSSResult | number)[]) => { - const cssText = values.reduce( - (acc, v, idx) => acc + textFromCSSResult(v) + strings[idx + 1], - strings[0]); - return new CSSResult(cssText, constructionToken); -}; +export const css = + (strings: TemplateStringsArray, ...values: (CSSResult|number)[]) => { + const cssText = values.reduce( + (acc, v, idx) => acc + textFromCSSResult(v) + strings[idx + 1], + strings[0]); + return new CSSResult(cssText, constructionToken); + }; diff --git a/src/lib/updating-element.ts b/src/lib/updating-element.ts index e09991d8..4701e3c9 100644 --- a/src/lib/updating-element.ts +++ b/src/lib/updating-element.ts @@ -447,7 +447,8 @@ export abstract class UpdatingElement extends HTMLElement { */ protected initialize() { this._saveInstanceProperties(); - // ensures first update will be caught by an early access of `updateComplete` + // ensures first update will be caught by an early access of + // `updateComplete` this._requestUpdate(); } @@ -492,10 +493,10 @@ export abstract class UpdatingElement extends HTMLElement { connectedCallback() { this._updateState = this._updateState | STATE_HAS_CONNECTED; - // Ensure first connection completes an update. Updates cannot complete before - // connection and if one is pending connection the `_hasConnectionResolver` - // will exist. If so, resolve it to complete the update, otherwise - // requestUpdate. + // Ensure first connection completes an update. Updates cannot complete + // before connection and if one is pending connection the + // `_hasConnectionResolver` will exist. If so, resolve it to complete the + // update, otherwise requestUpdate. if (this._hasConnectedResolver) { this._hasConnectedResolver(); this._hasConnectedResolver = undefined; diff --git a/src/test/lib/updating-element_test.ts b/src/test/lib/updating-element_test.ts index 9405765f..43990ddc 100644 --- a/src/test/lib/updating-element_test.ts +++ b/src/test/lib/updating-element_test.ts @@ -2215,7 +2215,7 @@ suite('UpdatingElement', () => { assert.equal(a.updatedCalledCount, 1); }); - test('early access of updateComplete waits until first update', async() => { + test('early access of updateComplete waits until first update', async () => { class A extends UpdatingElement { didUpdate = false; @@ -2237,37 +2237,37 @@ suite('UpdatingElement', () => { assert.isTrue(updated); }); - test('property reflects after setting attribute in same update cycle', async () => { - class A extends UpdatingElement { - - foo?: boolean; - bar?: string; + test( + 'property reflects after setting attribute in same update cycle', + async () => { + class A extends UpdatingElement { + foo?: boolean; + bar?: string; - static get properties() { - return { - foo: {type: Boolean, reflect: true}, - bar: {type: String, reflect: true} - }; - } - } - customElements.define(generateElementName(), A); - const a = new A(); - container.appendChild(a); - a.setAttribute('foo', ''); - a.removeAttribute('foo'); - a.foo = true; - await a.updateComplete; - assert.isTrue(a.hasAttribute('foo')); - a.setAttribute('bar', 'hi'); - a.bar = 'yo'; - await a.updateComplete; - assert.equal(a.getAttribute('bar'), 'yo'); - }); + static get properties() { + return { + foo: {type: Boolean, reflect: true}, + bar: {type: String, reflect: true} + }; + } + } + customElements.define(generateElementName(), A); + const a = new A(); + container.appendChild(a); + a.setAttribute('foo', ''); + a.removeAttribute('foo'); + a.foo = true; + await a.updateComplete; + assert.isTrue(a.hasAttribute('foo')); + a.setAttribute('bar', 'hi'); + a.bar = 'yo'; + await a.updateComplete; + assert.equal(a.getAttribute('bar'), 'yo'); + }); test('exceptions in `update` do not prevent further updates', async () => { let shouldThrow = false; class A extends UpdatingElement { - @property() foo = 5; updatedFoo = 0; @@ -2305,196 +2305,199 @@ suite('UpdatingElement', () => { assert.equal(a.updatedFoo, 20); }); - test('exceptions in `update` prevent `firstUpdated` and `updated` from being called', async () => { - let shouldThrow = false; - class A extends UpdatingElement { + test( + 'exceptions in `update` prevent `firstUpdated` and `updated` from being called', + async () => { + let shouldThrow = false; + class A extends UpdatingElement { + firstUpdatedCalled = false; + updatedCalled = false; + + update(changedProperties: Map) { + if (shouldThrow) { + throw new Error('test error'); + } + super.update(changedProperties); + } - firstUpdatedCalled = false; - updatedCalled = false; + firstUpdated() { + this.firstUpdatedCalled = true; + } - update(changedProperties: Map) { - if (shouldThrow) { - throw new Error('test error'); + updated(_changedProperties: Map) { + this.updatedCalled = true; + } } - super.update(changedProperties); - } - - firstUpdated() { - this.firstUpdatedCalled = true; - } - - updated(_changedProperties: Map) { - this.updatedCalled = true; - } - } - customElements.define(generateElementName(), A); - shouldThrow = true; - const a = new A(); - container.appendChild(a); - let threw = false; - try { - await a.updateComplete; - } catch (e) { - threw = true; - } - assert.isTrue(threw); - assert.isFalse(a.firstUpdatedCalled); - assert.isFalse(a.updatedCalled); - shouldThrow = false; - await a.requestUpdate(); - assert.isTrue(a.firstUpdatedCalled); - assert.isTrue(a.updatedCalled); - - }); - - test('exceptions in `shouldUpdate` do not prevent further updates', async () => { - let shouldThrow = false; - class A extends UpdatingElement { + customElements.define(generateElementName(), A); + shouldThrow = true; + const a = new A(); + container.appendChild(a); + let threw = false; + try { + await a.updateComplete; + } catch (e) { + threw = true; + } + assert.isTrue(threw); + assert.isFalse(a.firstUpdatedCalled); + assert.isFalse(a.updatedCalled); + shouldThrow = false; + await a.requestUpdate(); + assert.isTrue(a.firstUpdatedCalled); + assert.isTrue(a.updatedCalled); + }); - @property() foo = 5; - updatedFoo = 0; + test( + 'exceptions in `shouldUpdate` do not prevent further updates', + async () => { + let shouldThrow = false; + class A extends UpdatingElement { + @property() foo = 5; + updatedFoo = 0; + + shouldUpdate(changedProperties: Map) { + if (shouldThrow) { + throw new Error('test error'); + } + return super.shouldUpdate(changedProperties); + } - shouldUpdate(changedProperties: Map) { - if (shouldThrow) { - throw new Error('test error'); + updated(_changedProperties: Map) { + this.updatedFoo = this.foo; + } } - return super.shouldUpdate(changedProperties); - } - - updated(_changedProperties: Map) { - this.updatedFoo = this.foo; - } - } - customElements.define(generateElementName(), A); - const a = new A(); - container.appendChild(a); - await a.updateComplete; - assert.equal(a.updatedFoo, 5); - shouldThrow = true; - a.foo = 10; - let threw = false; - try { - await a.updateComplete; - } catch (e) { - threw = true; - } - assert.isTrue(threw); - assert.equal(a.foo, 10); - assert.equal(a.updatedFoo, 5); - shouldThrow = false; - a.foo = 20; - await a.updateComplete; - assert.equal(a.foo, 20); - assert.equal(a.updatedFoo, 20); - }); + customElements.define(generateElementName(), A); + const a = new A(); + container.appendChild(a); + await a.updateComplete; + assert.equal(a.updatedFoo, 5); + shouldThrow = true; + a.foo = 10; + let threw = false; + try { + await a.updateComplete; + } catch (e) { + threw = true; + } + assert.isTrue(threw); + assert.equal(a.foo, 10); + assert.equal(a.updatedFoo, 5); + shouldThrow = false; + a.foo = 20; + await a.updateComplete; + assert.equal(a.foo, 20); + assert.equal(a.updatedFoo, 20); + }); - test('exceptions in `updated` do not prevent further or re-entrant updates', async () => { - let shouldThrow = false; - let enqueue = false; - class A extends UpdatingElement { + test( + 'exceptions in `updated` do not prevent further or re-entrant updates', + async () => { + let shouldThrow = false; + let enqueue = false; + class A extends UpdatingElement { + @property() foo = 5; + updatedFoo = 0; - @property() foo = 5; - updatedFoo = 0; + changedProps?: PropertyValues; - changedProps?: PropertyValues; + updated(_changedProperties: Map) { + if (enqueue) { + enqueue = false; + this.foo++; + } + if (shouldThrow) { + shouldThrow = false; + throw new Error('test error'); + } + this.changedProps = _changedProperties; + this.updatedFoo = this.foo; + } - updated(_changedProperties: Map) { - if (enqueue) { - enqueue = false; - this.foo++; + get updateComplete(): Promise { + return super.updateComplete.then((v) => v || this.updateComplete); + } } - if (shouldThrow) { - shouldThrow = false; - throw new Error('test error'); + customElements.define(generateElementName(), A); + const a = new A(); + container.appendChild(a); + await a.updateComplete; + assert.equal(a.updatedFoo, 5); + shouldThrow = true; + a.changedProps = new Map(); + a.foo = 10; + let threw = false; + try { + await a.updateComplete; + } catch (e) { + threw = true; } - this.changedProps = _changedProperties; - this.updatedFoo = this.foo; - } - - get updateComplete(): Promise { - return super.updateComplete.then((v) => v || this.updateComplete); - } - } - customElements.define(generateElementName(), A); - const a = new A(); - container.appendChild(a); - await a.updateComplete; - assert.equal(a.updatedFoo, 5); - shouldThrow = true; - a.changedProps = new Map(); - a.foo = 10; - let threw = false; - try { - await a.updateComplete; - } catch (e) { - threw = true; - } - assert.isTrue(threw); - assert.isFalse(a.changedProps.has('foo')); - assert.equal(a.foo, 10); - assert.equal(a.updatedFoo, 5); - a.foo = 20; - await a.updateComplete; - assert.equal(a.changedProps.get('foo'), 10); - assert.equal(a.foo, 20); - assert.equal(a.updatedFoo, 20); - enqueue = true; - shouldThrow = true; - a.foo = 50; - threw = false; - try { - await a.updateComplete; - } catch (e) { - threw = true; - } - assert.isTrue(threw); - assert.equal(a.changedProps.get('foo'), 50); - assert.equal(a.foo, 51); - assert.equal(a.updatedFoo, 51); - }); - - test('exceptions in `performUpdate` do not prevent further updates', async () => { - let shouldThrow = false; - class A extends UpdatingElement { + assert.isTrue(threw); + assert.isFalse(a.changedProps.has('foo')); + assert.equal(a.foo, 10); + assert.equal(a.updatedFoo, 5); + a.foo = 20; + await a.updateComplete; + assert.equal(a.changedProps.get('foo'), 10); + assert.equal(a.foo, 20); + assert.equal(a.updatedFoo, 20); + enqueue = true; + shouldThrow = true; + a.foo = 50; + threw = false; + try { + await a.updateComplete; + } catch (e) { + threw = true; + } + assert.isTrue(threw); + assert.equal(a.changedProps.get('foo'), 50); + assert.equal(a.foo, 51); + assert.equal(a.updatedFoo, 51); + }); - @property() foo = 5; - updatedFoo = 0; + test( + 'exceptions in `performUpdate` do not prevent further updates', + async () => { + let shouldThrow = false; + class A extends UpdatingElement { + @property() foo = 5; + updatedFoo = 0; - updated(_changedProperties: Map) { - this.updatedFoo = this.foo; - } + updated(_changedProperties: Map) { + this.updatedFoo = this.foo; + } - performUpdate() { - return new Promise((resolve, reject) => { - super.performUpdate(); - if (shouldThrow) { - reject(); - } else { - resolve(); + performUpdate() { + return new Promise((resolve, reject) => { + super.performUpdate(); + if (shouldThrow) { + reject(); + } else { + resolve(); + } + }); } - }); - } - } - customElements.define(generateElementName(), A); - const a = new A(); - container.appendChild(a); - await a.updateComplete; - assert.equal(a.updatedFoo, 5); - shouldThrow = true; - a.foo = 10; - let threw = false; - try { - await a.updateComplete; - } catch (e) { - threw = true; - } - assert.isTrue(threw); - assert.equal(a.foo, 10); - assert.equal(a.updatedFoo, 10); - shouldThrow = false; - a.foo = 20; - await a.updateComplete; - assert.equal(a.foo, 20); - assert.equal(a.updatedFoo, 20); - }); + } + customElements.define(generateElementName(), A); + const a = new A(); + container.appendChild(a); + await a.updateComplete; + assert.equal(a.updatedFoo, 5); + shouldThrow = true; + a.foo = 10; + let threw = false; + try { + await a.updateComplete; + } catch (e) { + threw = true; + } + assert.isTrue(threw); + assert.equal(a.foo, 10); + assert.equal(a.updatedFoo, 10); + shouldThrow = false; + a.foo = 20; + await a.updateComplete; + assert.equal(a.foo, 20); + assert.equal(a.updatedFoo, 20); + }); }); diff --git a/src/test/lit-element_test.ts b/src/test/lit-element_test.ts index 7c118ee7..367a1cae 100644 --- a/src/test/lit-element_test.ts +++ b/src/test/lit-element_test.ts @@ -195,41 +195,41 @@ suite('LitElement', () => { assert.equal(window['litElementVersions'].length, 1); }); - test('exceptions in `render` throw but do not prevent further updates', async () => { - let shouldThrow = false; - class A extends LitElement { - - @property() foo = 5; - updatedFoo = 0; + test( + 'exceptions in `render` throw but do not prevent further updates', + async () => { + let shouldThrow = false; + class A extends LitElement { + @property() foo = 5; + updatedFoo = 0; - render() { - if (shouldThrow) { - throw new Error('test error'); + render() { + if (shouldThrow) { + throw new Error('test error'); + } + return html`${this.foo}`; + } } - return html`${this.foo}`; - } - - } - customElements.define(generateElementName(), A); - const a = new A(); - container.appendChild(a); - await a.updateComplete; - assert.equal(a.shadowRoot!.textContent, '5'); - shouldThrow = true; - a.foo = 10; - let threw = false; - try { - await a.updateComplete; - } catch (e) { - threw = true; - } - assert.isTrue(threw); - assert.equal(a.foo, 10); - assert.equal(a.shadowRoot!.textContent, '5'); - shouldThrow = false; - a.foo = 20; - await a.updateComplete; - assert.equal(a.foo, 20); - assert.equal(a.shadowRoot!.textContent, '20'); - }); + customElements.define(generateElementName(), A); + const a = new A(); + container.appendChild(a); + await a.updateComplete; + assert.equal(a.shadowRoot!.textContent, '5'); + shouldThrow = true; + a.foo = 10; + let threw = false; + try { + await a.updateComplete; + } catch (e) { + threw = true; + } + assert.isTrue(threw); + assert.equal(a.foo, 10); + assert.equal(a.shadowRoot!.textContent, '5'); + shouldThrow = false; + a.foo = 20; + await a.updateComplete; + assert.equal(a.foo, 20); + assert.equal(a.shadowRoot!.textContent, '20'); + }); }); From 4781b7f511048b4357a577a7eb442d00efe0767d Mon Sep 17 00:00:00 2001 From: Peter Burns Date: Thu, 18 Apr 2019 14:56:20 -0700 Subject: [PATCH 4/4] Disable unnecessary type assertions lint pass. --- tslint.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tslint.json b/tslint.json index 898af7e0..bb3dcb10 100644 --- a/tslint.json +++ b/tslint.json @@ -13,7 +13,7 @@ "no-internal-module": true, "no-trailing-whitespace": true, "no-var-keyword": true, - "no-unnecessary-type-assertion": true, + "no-unnecessary-type-assertion": false, "one-line": [ true, "check-open-brace",