1

I have two classes, Database and DatabaseEnc. I have a function which accepts Database class instance as a parameter. How do I ensure that the function only accepts Database class instance and not any other.

I know I can use instance of to check if instance is of Database inside the checkConn function. But I am looking for a more typescript based solution.

/* database.ts */

class Database {
    public state: string = null;
    constructor(state: string) {
        this.state = "some state";
    }
}

export default Database;

/* database_enc.ts */

class DatabaseEnc {
    public state: string = null;
        constructor() {
        this.state = "some other state";
    }
}

export default DatabaseEnc;

/* provider.ts */

import Database from "./database";
import DatabaseEnc from "./database_enc";

function checkConn(db: Database): void {
    Log.print(db);
}

// wrong, I should not be allowed to pass DatabaseEnc
// instance to the checkConn function parameter
const test = new DatabaseEnc();
checkConn(test);

// right, checkConn function should only accept Database
// class instance as a parameter
const test1 = new Database();
checkConn(test1);

// what is happening? I am allowed to pass any class's instance
// to the checkConn function.

I should not be allowed to pass any instance other than Database to the checkConn function.

Amir Saleem
  • 2,912
  • 3
  • 21
  • 35

1 Answers1

1

TypeScript is structurally typed, meaning if two types have the same structure, they're treated as the same. See the Type Compatibility section in the TS documentation. This is a convenient behaviour and is correct from the JS point of view, as both of those objects will work in the runtime, having the same properties.

That being said, you'll start getting type errors the moment those two classes diverge (eg. by adding a new property to the Database class), so you'll still get some kind of a type control later.

I would argue that you shouldn't try to hack around this behaviour and embrace it, as this is a good principle to work with ("program to interfaces, not implementations"). Rather than expecting some particular classes, you should expect object having a particular ability.

interface Checkable {
  checkConnection: (param: string) => boolean
}

class Database implements Checkable {
    // ...
    checkConnection(param: string) {
        return true
    }
}

// Is not Checkable.
class DatabaseEnc {
    // ...
}

// Allow all objects that can be checked.
function checkConn(db: Checkable): void {
    Log.print(db.check());
}

const test = new DatabaseEnc();
checkConn(test); // OK

const test1 = new Database();
checkConn(test1); // Error, since it doesn't implements the Checkable interface.

Mateusz Kocz
  • 4,492
  • 1
  • 25
  • 27