Skip to content

{composed:boolean} is missing in Event and EventInit interface within lib.dom.d.ts #18233

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Hotell opened this issue Sep 3, 2017 · 9 comments
Labels
Duplicate An existing issue was already created

Comments

@Hotell
Copy link

Hotell commented Sep 3, 2017

TypeScript Version: 2.5.2 ( and all prior version to latest )

Code

see error in TS playground

class Foo extends HTMLElement {
    constructor() {
        super()
        this.attachShadow({mode:'open'})
    }  
    emitCustomEvent() {
       // error
        this.shadowRoot.dispatchEvent(new Event('hello', {bubbles: true, composed: true}));
    }
    emitCustomEventWithExtractedConfig() {
        const worldEventConfig = {bubbles: true, composed: true}
        // no error --> ! this is strange behaviour of TSC, this should be error as well
        this.shadowRoot.dispatchEvent(new Event('world', worldEventConfig));
    }
}

Expected behavior:
{composed:boolean} should be defined ( this event config flag is needed when triggering custom events from shadow root to pierce outside the shadow.

Also what is very strange is that, when event config is initialized to a variable and used then as a reference within Event creation, TS won't throw error which is very strange behaviour indeed as from structure perspective, the composed property is still there and not allowed by current dom.lib.ts

Actual behavior:
add {composed: boolean} to Event and EventInit interfaces within dom.lib.ts

@Hotell Hotell changed the title {composed:boolean} is missing in Event and EventInit interface within lib.dom.ts {composed:boolean} is missing in Event and EventInit interface within lib.dom.d.ts Sep 3, 2017
@kitsonk
Copy link
Contributor

kitsonk commented Sep 4, 2017

Duplicate of: #17974 (search is your friend)

Covered by PR: microsoft/TypeScript-DOM-lib-generator#284

@Hotell
Copy link
Author

Hotell commented Sep 4, 2017

thanks, although I didn't find related issue via search, and yes I always look before creating issues if there is already one/similar created.

Still I think there is bug, not related to Event type, which I've described as well:

Also what is very strange is that, when event config is initialized to a variable and used then as a reference within Event creation, TS won't throw error which is very strange behaviour indeed as from structure perspective, the composed property is still there and not allowed by current dom.lib.ts

@kitsonk
Copy link
Contributor

kitsonk commented Sep 4, 2017

The behaviour around why something like this behaves the way it does:

interface FooOptions {
    foo?: string;
}

declare function foo(options?: FooOptions): void;

foo({
    foo: 'bar',
    bar: 123 // error
});

const options = { foo: 'bar', bar: 123 };

foo(options); // no error

const guardedOptions: FooOptions = { foo: 'bar', bar: 123 }; // error

Has to do with the challenges of dealing with a structural type system. IIRC prior to TypeScript 1.6, an object literal could have excess properties, as that is allowed in a structural type system. That of course causes a lot of potentially unintentional mistakes (though if the interfaces are correct, excess properties shouldn't matter). Because strictly speaking { foo: 'bar', bar: 123 } is actually assignable to the type of { foo: string }.

Because this can be surprising the decision was made to check for excess properties on the assignment of the object literal, but follow the right way of dealing with assignment in other locations. This still means when you have a variable that is contextually typed, it follows the proper assignment rules, but if you assert the type, instead of contextually infer it, the fresh object literal type is checked to see if it has excess properties.

So this is working as designed.

@alan-agius4
Copy link
Contributor

alan-agius4 commented Sep 5, 2017

Thanks for nice explanation above.

So, what you be the ideal way to remove excess properties?

using object deconstruction or just use type assertions?

Option 1

const { genericErrorCode, ...someErrorConfig } = errorConfig;
return {
    ...someErrorConfig,
    code,
    data
};

or

Option 2

return {
    ...errorConfig,
    code,
    data
} as AppError;

@kitsonk
Copy link
Contributor

kitsonk commented Sep 5, 2017

So, what you be the ideal way to remove excess properties?

Question is why you need to remove excess properties... but there are many ways. If you are trying to catch errors, guard the types when authoring "fresh" objects, like I did above:

const guardedOptions: FooOptions = { foo: 'bar', bar: 123 }; // error

@Hotell
Copy link
Author

Hotell commented Sep 5, 2017

First of thanks so much for thorough explanation @kitsonk didn't know that it works this way !

about:

Question is why you need to remove excess properties... but there are many ways. If you are trying to catch errors, guard the types when authoring "fresh" objects, like I did above:

const guardedOptions: FooOptions = { foo: 'bar', bar: 123 }; // error

Well now with this style, we are getting to "Java" style -> explicitly annotate that string is a string which is a big no no IMHO. ( even there are lint rules within TSLint that will error on this explicit annotation on Classes properties for instance )

Hopefully this can be resolved somehow in future releases of TS

@alan-agius4
Copy link
Contributor

alan-agius4 commented Sep 5, 2017

@kitsonk I need to remove excessive properties, to make typescript compile, actually either remove the properties or use the type assertion using the as myInterface.

I am just asking what would be the recommended way :)

@kitsonk
Copy link
Contributor

kitsonk commented Sep 5, 2017

Hopefully this can be resolved somehow in future releases of TS

It won't be fixable until there is some level of support for co-variant parameters, which is a really difficult thing to introduce. It can be surprising behaviour, but why it is surprising is to permit other functionality that would be really annoying if TypeScript didn't support. This is explained in the FAQ Why are function parameters bivariant?

@mhegazy mhegazy added the Duplicate An existing issue was already created label Sep 5, 2017
@mhegazy
Copy link
Contributor

mhegazy commented Sep 20, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@mhegazy mhegazy closed this as completed Sep 20, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants