Skip to content

Don't emit abstract members #40632

Closed
@Qwertiy

Description

@Qwertiy

TypeScript Version: 3.7 - 4.1.0-dev.20200918

Search Terms:
abstract properties emit useDefineForClassFields

Code

Turn on useDefineForClassFields

abstract class A {
    protected abstract x: number;
}

Expected behavior:

Abstract members are hint for typescript and they don't emit any code. So expected compiled code will be:

"use strict";
class A {
}

Actual behavior:

"use strict";
class A {
    constructor() {
        Object.defineProperty(this, "x", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
    }
}

Playground Link:
https://www.typescriptlang.org/play?useDefineForClassFields=true&ts=4.1.0-dev.20200918#code/IYIwzgLgTsDGEAJYBthjAgggg3gKAUIQAcoB7CAU3koBMFRIZ4EAPALgQDsBXAWxCUoAbjwBfIA

Consequence of such generation:

There is a larger problem caused by compiling abstract member.

There are 2 ways of override - using property or using getter/setter and they both should be (and are according to ts) compatible with abstract member. But only one of them is fine in runtime.

Code

Turn on useDefineForClassFields

abstract class A {
    protected readonly abstract x: number;

    public doSmth() {
        console.log(this.x)
    }
}

class B extends A {
    protected x = 10
}

class C extends A {
    protected get x() { return 7 }
}

new B().doSmth()
new C().doSmth()

Run compiled code

Expected behavior:

Output:

10 
7

Compiled code:

"use strict";
class A {
    doSmth() {
        console.log(this.x);
    }
}
class B extends A {
    constructor() {
        super(...arguments);
        Object.defineProperty(this, "x", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 10
        });
    }
}
class C extends A {
    get x() { return 7; }
}
new B().doSmth();
new C().doSmth();

Actual behavior:

Ouptut:

10 
undefined

Compiled code:

"use strict";
class A {
    constructor() {
        Object.defineProperty(this, "x", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: void 0
        });
    }
    doSmth() {
        console.log(this.x);
    }
}
class B extends A {
    constructor() {
        super(...arguments);
        Object.defineProperty(this, "x", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: 10
        });
    }
}
class C extends A {
    get x() { return 7; }
}
new B().doSmth();
new C().doSmth();

Playground Link:
https://www.typescriptlang.org/play?useDefineForClassFields=true&ts=4.1.0-dev.20200918#code/IYIwzgLgTsDGEAJYBthjAgggg3gKAUIQAcoB7CAU3koBMEpLhayA7ZATwVEhngQAeALgSsArgFsQlKAG48BIsTEhkAS1gIWAZQkQAFgAoAlLkVEisNmDLJKAOmRkA5oYNqw9gcfMIAvngBeChoGABCCJQCVKy0GNj4FqQU1FT0AggAvAgAjAAMgQoh6AgAwpHRlLHxZknkVDT0zpSIAia4DC1iUKwIAOz+hXislADuCGEm9jp6Rj4j46VTMwYmQA

Related Issues:
#31225

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptFix AvailableA PR has been opened for this issueHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions