How can i avoid a function to be overridden in the Child Class in TypeScript ?

Update for TS 4.3 and above

Typescript 4.3 adds a new compiler option called noImplicitOverride in this PR. This makes it an error to mistakenly override class methods without the override keyword

class Base{
    method() {}
    method2 () {}
} 

class Derived extends Base {
    method() {} // err 
    override method2() {} // ok
} 

(playground does not support the option yet, but works in vs code)

Original answer pre 4.3

There is no way to prevent a public/protected member from beeing overriden. The compiler will trigger an error if you to this with private members only. A feature for this has been proposed but not implemented


In Javascript the short answer is, "yes, we can". I have no experience with Typescript but I understand it is a superset of Javascript so I guess that means if you can do it in Javascript then you can do it in Typescript - please correct me if I am wrong.

Running in nodejs in interactive console mode:

class A {
    constructor(){
        Reflect.defineProperty(this, 'protectedFn', {
            value: ()=>{ return "hello" },
            configurable: false, 
            writable: false,
            enumerable: true
        })
    }
}
class B extends A {
    constructor(){
        super()
        this.protectedFn=()=>{}
    }
}
class C extends A {
    constructor(){
        super()
        Reflect.defineProperty(this, 'protectedFn', {
            value: (v)=>{ return "goodbye" }
        })
    }
}
class D extends A {
    constructor(){
        super()
        Reflect.deleteProperty(this, 'protectedFn')
    }
}
let a = new A();
let b = new B();
let c = new C();
let d = new D();
a.protectedFn()

c.protectedFn()

d.protectedFn()

results in

> let a = new A();

> let b = new B();
Thrown:
TypeError: Cannot assign to read only property 'protectedFn' of object '#<B>'
    at new B (repl:4:19)

> let c = new C();

> let d = new D();

> a.protectedFn()
'hello'

> c.protectedFn()
'hello'

> d.protectedFn()
'hello'

We see the constructor of B invoked a throw using the simple assignment form.

The constructor of C didn't throw, but it silently failed. Ouch. The return result of Replace.defineProperty is actually false and should be checked.

Same with D.

Interestingly, using ES5 Object.* instead ES6 Replace.* results in a throw upon failure. Also Object.deleteProperty does not exist.

Tags:

Typescript