5

I am creating a data model paradigm with typescript. I store different types of data in different places (SQL, a local cache). I want to create an abstract class that contains all of the methods I would need for any type of data storage (create, find, update, count, destroy). This way I could extend that class and implement it differently for different types of storage and the compiler would warn me if I was missing a method. I would then extend one of those implementations in a class describing the data model. However, some of the methods I need (such as find and create) are static. I know typescript does not support abstract static methods. Is there something similar to abstract methods I could use so the compiler warns me about missing methods?

I would also like these static methods to be generic and typed the same as the class. I know this makes no sense for a standard generic class. However, since this class will always be extended and never instantiated, could I type the generic class when I extend it, automatically updating the generic type on the static methods?

2 Answers 2

5

Is there something similar to abstract methods I could use so the compiler warns me about missing methods

Not built in, so you will not get good errors by simply

// WILL NOT COMPILE. SAMPLE
class Foo {
    abstract static X() { } 
}

class Bar extends Foo { // Error here please
}

However you can use tricks like type compatability to ensure:

interface FooAbstract {
    X(): any;
}
let _ensureAbstractMatch: FooAbstract;
class Foo {
}

class Bar extends Foo {
}
_ensureAbstractMatch = Bar; // Error missing method

Sample implementation:

interface FooAbstract {
    X(): any;
}
let _ensureAbstractMatch: FooAbstract;
class Foo {
}

class Bar extends Foo {
    static X() { }
}
_ensureAbstractMatch = Bar; // OKAY
Sign up to request clarification or add additional context in comments.

2 Comments

I think it might be simpler to use the singleton pattern, creating a generic singleton object with methods in place of static methods then type that generic object with an interface or abstract class that has the necessary methods for each object. Do you think that is a good approach?
Do you think that is a good approach If it works, then yes 🌹
0

I know typescript does not support abstract static methods. Is there something similar to [static] abstract methods I could use ...?

Researching abstract statics also. Answer is abstract static declaration is not yet supported, but you can do something close: Require the class object to implement an abstract class which is equivalent to saying it's statics must implement the interface. Example taking some parts I learnt from a few other answers 1, 2, 3:

// The static interface.
abstract class ResourceContainer { 
  abstract create(resource: Creator): Resource
  abstract count(query?: Query): number
  abstract find(query: Query): FindResult
}
// The instance interface.
abstract class Resource { 
  abstract read(): ReadResult
  abstract update(resource: Updator): ReadResult
  abstract delete(): void
}
// Attach newable to type corresponding to a concrete class - because Typescript ...
type NewableResource = ({new (...args: any): any} & ResourceContainer) 

const FooResource: NewableResource = class extends Resource {
  static create(resource: Creator): Resource { console.debug('create'); return new this(); }
  static find(query?: Query) { console.debug('find'); }
  static count(query?: Query) { console.debug('count'); return 0; }
  read() { console.debug('read'); }
  update(resource: Updator) { console.debug('update'); }
  delete() { console.debug('delete'); }
}

// TODO: flesh out these utility types ..
type Query = unknown;
type FindResult = unknown;
type ReadResult = unknown;
type Updator = unknown;
type Creator = unknown;

// Get the *type* of an class object *value*.
type FooResource = InstanceType<typeof FooResource> 

const x: FooResource = FooResource.create({});
x.read()

Alternatively, if your so inclined, you could just do this:

abstract class Resource {
  static create(resource: Creator): Resource { throw NotImplementedError() }
  static count(query?: Query): number { throw NotImplementedError() }
  static find(query: Query): FindResult { throw NotImplementedError() }
  abstract read(): ReadResult
  abstract update(resource: Updator): ReadResult
  abstract delete(): void
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.