Typescript static methods in interface

How to declare interface with static method and constructor signature in TypeScript?

I have two classes with common static method. What’s the best way to add common interface which includes static method implementation and constructor signature? I wrote BitcoinHDWallet and EthereumHDWallet classes which implement wallet logic for corresponded blockchains. I would like to add common interface HDWallet which going to describe logic to work with both of them so user can do:

 const multiWallet: Array = []; multiWallet[0] = new BitcoinHDWallet(. ); multiWallet[1] = new EthereumHDWallet(. ); 

These two classes share some common static methods. 0) If I use abstract class as the way to describe interface, I don’t know how to add constructor signature. 1) If I use interface , I can’t add static method implementation. Ideally, I want to do something like that:

abstract class HDWallet < /** * Return new random mnemonic seed phrase */ static generateMnemonic(): string < return Bip39.generateMnemonic(); >constructor(bip39SeedPhrase: string, password?: string, testnet?: boolean); abstract getAddress(addressIndex?: number) : string; abstract async getBalance(address? : string) : Promise; . > class BitcoinHDWallet extends HDWallet class EthereumHDWallet extends HDWallet

1 Answer 1

There is no to do this out of the box. The abstract class is the closest thing to what you want, but it will indeed not allow you to check that the type has a specific constructor.

Читайте также:  Include php file with variables

One way to do this is to add an extra type parameter to the class. This can be constrained to typeof HDWallet which will represent the constructor signature of the base class. Derived classes must pass themselves as this extra parameter and then their constructor signature will be checked to be compatible with the base class signature:

abstract class HDWallet  < /** * Return BIP39 12 words new random mnemonic seed phrase */ static generateMnemonic(): string < return ""; >constructor(bip39SeedPhrase: string, password?: string, testnet?: boolean) < >abstract getAddress(addressIndex?: number) : string; abstract async getBalance(address? : string) : Promise; > class BitcoinHDWallet extends HDWallet  < getAddress(addressIndex?: number) : string < return "">async getBalance(address?: string): Promise  < return Promise.resolve(0);>> class EthereumHDWallet extends HDWallet  < /// error constructor(testnet?: boolean) < super("", "", false) >getAddress(addressIndex?: number) : string < return "">async getBalance(address?: string): Promise  < return Promise.resolve(0);>> 

Note using interfaces, you can describe the static part of the class as well as the instance type, depends what you are trying to validate:

interface HDWalletClass < generateMnemonic(): string new (bip39SeedPhrase: string, password?: string, testnet?: boolean): < getAddress(addressIndex?: number): string; getBalance(address?: string): Promise; > > abstract class HDWallet < /** * Return BIP39 12 words new random mnemonic seed phrase */ static generateMnemonic(): string < return ""; >constructor(bip39SeedPhrase: string, password?: string, testnet?: boolean) < >abstract getAddress(addressIndex?: number) : string; abstract async getBalance(address? : string) : Promise; > class BitcoinHDWallet extends HDWallet < getAddress(addressIndex?: number) : string < return "">async getBalance(address?: string): Promise  < return Promise.resolve(0);>> class EthereumHDWallet extends HDWallet < /// error constructor(testnet?: boolean) < super("", "", false) >getAddress(addressIndex?: number) : string < return "">async getBalance(address?: string): Promise  < return Promise.resolve(0);>> let a: HDWalletClass = BitcoinHDWallet; //ok let b: HDWalletClass = EthereumHDWallet; // err 

Источник

How to declare an interface with static method?

Now we are able to set the as and as using the following code: Enter fullscreen mode Exit fullscreen mode Last, as I mentioned earlier, the class has methods that how the object should act. If we run the method, it will execute the following statement: Enter fullscreen mode Exit fullscreen mode What is an interface in TypeScript? An interface is a structure that acts like a contract in your application, or the syntax for classes to follow.

Читайте также:  Python capitalize all words

How to declare an interface with static method?

I want to declare an alternative constructor in interface — baz in IFoo , but seems like it’s impossible in TypeScript:

interface IFoo < bar(): boolean; static baz(value): IFoo; >class Foo implements IFoo < constructor(private qux) <>bar(): boolean < return this.qux; >static baz(value): IFoo < return new Foo(value); >> 

What is the way to do that and have a proper type checking for baz ?

you can do this with anonymous classes:

export const MyClass: StaticInterface = class implements InstanceInterface

Your example:

interface IFooStatic < baz(value): IFoo; >interface IFoo < bar(): boolean; >const Foo: IFooStatic = class implements IFoo < constructor(private qux) <>bar(): boolean < return this.qux; >static baz(value): IFoo < return new Foo(value); >> 

You can’t define a static in an Interface in TypeScript. If you want to have type checking for the factory method just remove static keyword.

You can still use the factory method like this over the prototype property:

var FootInstance = Foo.prototype.baz(‘test’);

Interfaces do not support static methods.

You can’t use abstract classes for your problem too:

interface IFoo < bar(): boolean; >abstract class FooBase < abstract static baz(value): IFoo; // this is NOT allowed >class Foo extends FooBase < constructor(private qux) < super(); >bar(): boolean < return this.qux; >static baz(value): IFoo < return new Foo(value); >> 

When and how to use interfaces and classes in TypeScript

Written by Gapur Kassym ✏️

Interfaces and classes are the fundamental parts of object-oriented programming (OOP). TypeScript is an object-oriented JavaScript language that, from ES6 and later, supports OOP features like interface, class, and encapsulation.

But when should we use interfaces, classes, or both at the same time? If you are a new or confused using interfaces and classes, this piece is for you.

In this article, I’ll show you what interfaces and classes are and when to use one or both of them in TypeScript.

What is a class in TypeScript?

Before we get started, we need to know what a TypeScript class is. In object-oriented programming, a class is a blueprint or template by which we can create objects with specific properties and methods.

Typescript provides additional syntax for type checking and converts code to Clean JavaScript that runs on any platform and browser. Classes are involved in all stages of code. After converting the TypeScript code to a JavaScript file, you can find them in the final files.

The class defines the template of the object, or what it is and what it does. Let’s create a simple class with properties and methods so we can see how it will behave.

First, I’m going to create a Developer class through the following lines of code:

class Developer  name?: string; // string or undefined position?: string; // string or undefined > 

We describe the class with properties name and position . They contain types like string and undefined .

Next, let’s create an object via the Developer class using the new keyword:

const developer = new Developer(); developer.name // it outputs undefined developer.position // it outputs undefined 

When we call developer.name , it returns undefined because we didn’t assign initial values. In order to create an object with values in TypeScript, we can use the constructor method. The constructor method is used to initialize and create objects.

Now we update our Developer class with the following code:

class Developer  name: string; // only string position: string; // only string constructor(name: string, position: string)  this.name = name; this.position = position; > > 

In the code above, we added the constructor method to initialize the properties with values.

Now we are able to set the name as Gapur and position as Frontend Developer using the following code:

const developer = new Developer("Gapur", "Frontend Developer"); developer.name // it outputs Gapur developer.position // it outputs Frontend Developer 

Last, as I mentioned earlier, the class has methods that how the object should act. In this case, any developer develops applications, therefore, the Developer class has the method develop .

Thus, a developer object can perform a development action:

class Developer  name: string; position: string; constructor(name: string, position: string)  this.name = name; this.position = position; > develop(): void  console.log('develop an app'); > > 

If we run the develop method, it will execute the following console.log statement:

developer.develop() // it outputs develop an app 

What is an interface in TypeScript?

An interface is a structure that acts like a contract in your application, or the syntax for classes to follow. The interface is also known as duck printing, or subtyping.

The interface includes an only method and field declarations without implementation. We can’t use it to create anything. A class that implements an interface must have all fields and methods. Therefore, we use them for type checking.

When TypeScript converts all code to JavaScript, the interface will disappear from the JavaScript file. Therefore, it is a helpful tool during the development phase.

We should use an interface for the following:

  • Validating specific structure of properties
  • Objects as parameters
  • Objects returned from functions

Now, let’s declare the interface through the following lines of code:

interface InterfaceName  // variables; // methods; > 

We can only contain declarations of variables and methods in the body of the interface. Let’s create an IDeveloper interface for the previous Developer class:

interface IDeveloper  name: string position: string develop: () => void > class Developer implements IDeveloper  name: string; position: string; constructor(name: string, position: string)  this.name = name; this.position = position; > develop(): void  console.log('develop an app'); > > 

In the above code, our IDeveloper interface contains the variables name and position . It also includes the develop method. So the Developer class implements the IDeveloper interface. Thus, it must define two variables and a method.

If the Developer class doesn’t implement any variables, TypeScript will show an error:

class Developer implements IDeveloper  // error Class 'Developer' incorrectly implements interface 'IDeveloper'. name: string; constructor(name: string, position: string)  this.name = name; this.position = position; > develop(): void  console.log('develop an app'); > > 

Interfaces vs classes

So when should we use classes and when should we use interfaces?

Before we start, I want to share with you the powerful TypeScript static property that allow us to use fields and methods of classes without creating instance of class.

I am going to make a class with a static method using the previous Developer class:

class Developer  static develop(app:  name: string, type: string >)  return  name: app.name, type: app.type >; > > 

Now, we can just call the Developer.develop() method without instantiating the class:

Developer.develop( name: 'whatsapp', type: 'mobile' >) // outputs: 

Also, we can use classes for type checking in typescript. Let’s create an App class using the following code:

class App  name: string; type: string; constructor(name: string, type: string)  this.name = name; this.type = type; > > 

Let’s modify our Developer class:

class Developer  static develop(app: App)  return  name: app.name, type: app.type >; // output the same > > 

Now I will make an App instance and invoke Developer.develop() with an argument object:

const app = new App('whatsapp', 'mobile'); Developer.develop(app); // outputs the same: 

Developer.develop(app) and Developer.develop(< name: 'whatsapp', type: 'mobile' >) output the same content. This is awesome, but the second approach is more readable and flexible.

Plus, we can check the type of arguments. Unfortunately, to do so, we need to create an object. So how can we improve it? This is where the interface comes in!

First, I am going to change the App class to an interface with the following code:

interface App  name: string type: string > class Developer  static develop(app: App)  return  name: app.name, type: app.type >; // output the same > > 

In the code above, we didn’t change the body of the Developer class and didn’t create an instance of App , but the result was the same. In this case, we saved a lot of time and code typing.

Conclusion

When should we use classes and interfaces? If you want to create and pass a type-checked class object, you should use TypeScript classes. If you need to work without creating an object, an interface is best for you.

Eventually, we opened two useful approaches: blueprints and contracts. You can use both of them together or just one. It is up to you.

Thanks for reading — I hope you found this piece useful. Happy coding!

Writing a lot of TypeScript? Watch the recording of our recent TypeScript meetup to learn about writing more readable code.

TypeScript meetup header

Typescript automatically get interface properties in a class, We can however use a function that returns a class as the base type of our class. This function can lie a little bit and claim it implements the

Typescript, interface inside class?

I could not find any article about this.

How can i define a nested interface inside a class ?

export class Car < export interface Config < name : string >constructor ( config : Config ) < >> 

You can’t do it directly. But you can use namespace-class merging to achieve the desired effect at least from the point of you of an external consumer:

export class Car < constructor(config: Car.Config) < >> namespace Car < export interface Config < name: string >> let c: Car.Config; 

Источник

Оцените статью