While TypeScript's flow-analyzer is very impressive and allows for types to be refined, narrowed, or widened within a scope when you use type-guard type predicate functions, typeof
and instanceof
, TypeScript still doesn't yet track all changes to a variable's type which should otherwise be inferable from use of the in
operator or Object.defineProperty
.
(UPDATE: So TypeScript 4+ does use in
for narrowing, but only to discriminate between possibilities in union types)
...so until TypeScript supports following Object.defineProperty
you can workaround that limitation with some manual tweaks:
Manually defining a new type
that combines the DOM's built-in HTMLDivElement
type with a singular info: { readonly text: string }
type.
- My code below also defines
info
's Type as type MyInfo
instead of being anonymous.
- I call this
HTMLDivElementWithInfo
.
Change the divModify
function to return HTMLDivElementWithInfo
instead of HTMLDivElement
.
Add a type-assertion to Object.defineProperty
's return-value (which is an alias of div
) named div2
as HTMLDivElementWithInfo
.
After all that, tsc
will now allow you to dereference div.info
.
Like so:
Playground link.
type MyInfo = { readonly text: string; };
type HTMLDivElementWithInfo = HTMLDivElement & { info: MyInfo };
function createDivWithInfo(): HTMLDivElementWithInfo {
const div = document.createElement("div");
div.id = "test";
div.classList.add("d-flex");
const initialInfoPropValue = { text: "Hello word" };
const div2 = Object.defineProperty( div, "info", { value: initialInfoPropValue } ) as HTMLDivElementWithInfo;
console.log( div2 );
console.log( div2.info );
return div2;
}
const d = createDivWithInfo();
console.log( d.info );