The element returned by createElement is an HTML element with all of the @api-decorated properties from the provided component class. And we see, from usage, that it is very common for projects to use these additional props in their code. To improve the TypeScript developer experience in LWC v7, we updated the type signature to include the props in addition to the base HTMLElement interface. However, due to a limitation of TypeScript, it is not possible to detect which component props have been decorated. Consequently, we made the decision to include all component props on the return type, even though they don't all exist on the runtime object. This facilitates authoring TypeScript code when using the @api props, but it may cause confusion if users try to access the other props that don't actually exist.
Steps to Reproduce
// x/foo/foo.ts
import { api, LightningElement } from 'lwc';
export default class extends LightningElement {
@api exposedProp = 'hello';
privateProp = 'secret';
}
// app.ts
import { createElement } from 'lwc';
import Foo from 'x/foo';
const foo = createElement('x-foo', { is: Foo });
console.log(foo.exposedProp) // ok
console.log(foo.privateProp)
// ^^^ should be a type error, but TypeScript thinks it's a string
Expected Results
The code should result in a type error: "Property 'privateProp' does not exist on type 'LightningHTMLElement'."
Actual Results
TypeScript thinks that foo.privateProp is a string, even though it doesn't actually exist at runtime.
Workaround
Users who want to have truly accurate types can provide an explicit generic parameter to createElement, and the returned type will include only the props exposed.
// These will have no additional properties, i.e. be just `HTMLElement`
const foo = createElement<object>('x-foo', { is: Foo });
const foo = createElement<LightningElement>('x-foo', { is: Foo });
// This will have only `exposedProp` available, *not* `privateProp`
const foo = createElement<{ exposedProp: string }>('x-foo', { is: Foo });
console.log(foo.exposedProp) // ok
console.log(foo.privateProp) // type error, as desired!
Users Affected
This bug only impacts projects written in TypeScript.
Description
The element returned by
createElement
is an HTML element with all of the@api
-decorated properties from the provided component class. And we see, from usage, that it is very common for projects to use these additional props in their code. To improve the TypeScript developer experience in LWC v7, we updated the type signature to include the props in addition to the baseHTMLElement
interface. However, due to a limitation of TypeScript, it is not possible to detect which component props have been decorated. Consequently, we made the decision to include all component props on the return type, even though they don't all exist on the runtime object. This facilitates authoring TypeScript code when using the@api
props, but it may cause confusion if users try to access the other props that don't actually exist.Steps to Reproduce
Expected Results
The code should result in a type error: "Property 'privateProp' does not exist on type 'LightningHTMLElement'."
Actual Results
TypeScript thinks that
foo.privateProp
is a string, even though it doesn't actually exist at runtime.Workaround
Users who want to have truly accurate types can provide an explicit generic parameter to
createElement
, and the returned type will include only the props exposed.Users Affected
This bug only impacts projects written in TypeScript.
Version