2

I'm using Knex.js with TypeScript for database access.

Table

  • uid (UUID, auto-generated by Postgres)
  • name (varchar)

Model

    interface User {
        uid: string | null;
        name: string;
    }

Repository

    class UserRepository {
        public async insert(user: User): Promise<void> {
            await knex('user').insert(user);
        }
    }

Usage

function someRouteHandler(req, res) {
    const repo = new UserRepository(...)

    // Next line will error out due to the object literal
    // not having the uid property
    repo.insert({
        //uid: null // satisfies interface constraint but errors during insert
        name: req.body.name,
    });
}

Problem

The only way I see this working is to modify the repository class methods to explicitly say which fields I need to insert:

public async insert(user: User): Promise<void> {
    await knex('user').insert({
        name: user.name,
    });
}

Unfortunately, this adds maintenance efforts since every time I modify the model I also need to modify the methods that do the queries to reflect the changed properties.

Is there a cleaner way of doing this?

2
  • 1
    What is the actual value of the uid you're populating the property with? If it's a UUID, you could generate the UUID in the application layer and pass the value to the insert method, instead of passing null.
    – Andy
    Jul 28, 2020 at 6:33
  • Have you tried with undefined instead of null? In any case, as far as I can tell this has nothing to do with TS itself, it's a quirk of the library
    – gcali
    Aug 27, 2020 at 7:34

2 Answers 2

0

The best way I know is, you can create an alias of that property at the beginning of the method or at initialization and whenever you make changes in your model, you will just have to make changes in that alias property.

0

As @Andy wrote in the comment, you could move the creation of the UUID from the Database into the application layer. To tell the truth, i would stick with the database generation, its less effort and its more failsafe.

You could try a two interfaces approach

interface MyModel {
  name: string;
}

interface MyModelDatabase extends MyModel {
  uuid: string;
}

Then you can use MyModel when you insert and MyModelDatabase when you work with querys from the database.
Be aware that i omit the "null" at the UUID in the interface. The reason is, that your database will always generate that uuid, therefor it will never be null.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.