[typescript] How to define static property in TypeScript interface

I just want to declare a static property in typescript interface? I have not found anywhere regarding this.

interface myInterface {
  static Name:string;
}

Is it possible?

This question is related to typescript

The answer is


You can merge interface with namespace using the same name:

interface myInterface { }

namespace myInterface {
  Name:string;
}

But this interface is only useful to know that its have property Name. You can not implement it.


I found a way to do this (without decorators) for my specific use case.

The important part that checks for static members is IObjectClass and using cls: IObjectClass<T> in the createObject method:

//------------------------
// Library
//------------------------
interface IObject {
  id: number;
}
interface IObjectClass<T> {
  new(): T;
  table_name: string;
}
function createObject<T extends IObject>(cls: IObjectClass<T>, data:Partial<T>):T {
  let obj:T = (<any>Object).assign({},
    data,
    {
      id: 1,
      table_name: cls.table_name,
    }
  )
  return obj;
}

//------------------------
// Implementation
//------------------------
export class User implements IObject {
  static table_name: string = 'user';
  id: number;
  name: string;
}

//------------------------
// Application
//------------------------
let user = createObject(User, {name: 'Jimmy'});
console.log(user.name);

Though static keyword not supported in interface in Typescript but we can achieve it by creating a function interface that has static member.

In my following code I have created a function interface Factory that has two static members serialNumber and printSerial.

// factory is a function interface
interface Factory<T> {
    (name: string, age: number): T;

    //staic property
    serialNumber: number;

    //static method
    printSrial: () => void;
}

class Dog {
    constructor(public name: string, public age: number) { }
}

const dogFactory: Factory<Dog> = (name, age) => {
    return new Dog(name, age);
}

// initialising static members

dogFactory.serialNumber = 1234;
dogFactory.printSrial = () => console.log(dogFactory.serialNumber);


//instance of Dog that DogFactory creates
const myDog = dogFactory("spike", 3);

//static property that returns 1234
console.log(dogFactory.serialNumber)

//static method that prints the serial 1234
dogFactory.printSrial();

Yes, it is possible. Here is the solution

export interface Foo {

    test(): void;
}

export namespace Foo {

    export function statMethod(): void {
        console.log(2);
    }

}

I implemented a solution like Kamil Szot's, and it has an undesired effect. I have not enough reputation to post this as a comment, so I post it here in case someone is trying that solution and reads this.

The solution is:

interface MyInterface {
    Name: string;
}

const MyClass = class {
    static Name: string;
};

However, using a class expression doesn't allow me to use MyClass as a type. If I write something like:

const myInstance: MyClass;

myInstance turns out to be of type any, and my editor shows the following error:

'MyClass' refers to a value, but is being used as a type here. Did you mean 'typeof MyClass'?ts(2749)

I end up losing a more important typing than the one I wanted to achieve with the interface for the static part of the class.

Val's solution using a decorator avoids this pitfall.


The other solutions seem to stray from the blessed path and I found that my scenario was covered in the Typescript documentation which I've paraphrased below:

interface AppPackageCheck<T> {
  new (packageExists: boolean): T
  checkIfPackageExists(): boolean;
}

class WebApp {
    public static checkIfPackageExists(): boolean {
        return false;
    }

    constructor(public packageExists: boolean) {}
}

class BackendApp {
    constructor(public packageExists: boolean) {}
}

function createApp<T>(type: AppPackageCheck<T>): T {
    const packageExists = type.checkIfPackageExists();
    return new type(packageExists)
}

let web = createApp(WebApp);

// compiler failure here, missing checkIfPackageExists
let backend = createApp(BackendApp); 

@duncan's solution above specifying new() for the static type works also with interfaces:

interface MyType {
    instanceMethod();
}

interface MyTypeStatic {
    new():MyType;
    staticMethod();
}

You can define interface normally:

interface MyInterface {
    Name:string;
}

but you can't just do

class MyClass implements MyInterface {
    static Name:string; // typescript won't care about this field
    Name:string;         // and demand this one instead
}

To express that a class should follow this interface for its static properties you need a bit of trickery:

var MyClass: MyInterface;
MyClass = class {
    static Name:string; // if the class doesn't have that field it won't compile
}

You can even keep the name of the class, TypeScript (2.0) won't mind:

var MyClass: MyInterface;
MyClass = class MyClass {
    static Name:string; // if the class doesn't have that field it won't compile
}

If you want to inherit from many interfaces statically you'll have to merge them first into a new one:

interface NameInterface {
    Name:string;
}
interface AddressInterface {
    Address:string;
}
interface NameAndAddressInterface extends NameInterface, AddressInterface { }
var MyClass: NameAndAddressInterface;
MyClass = class MyClass {
    static Name:string; // if the class doesn't have that static field code won't compile
    static Address:string; // if the class doesn't have that static field code won't compile
}

Or if you don't want to name merged interface you can do:

interface NameInterface {
    Name:string;
}
interface AddressInterface {
    Address:string;
}
var MyClass: NameInterface & AddressInterface;
MyClass = class MyClass {
    static Name:string; // if the class doesn't have that static field code won't compile
    static Address:string; // if the class doesn't have that static field code won't compile
}

Working example


Another option not mentioned here is defining variable with a type representing static interface and assigning to it class expression:

interface MyType {
    instanceMethod(): void;
}

interface MyTypeStatic {
    new(): MyType;
    staticMethod(): void;
}

// ok
const MyTypeClass: MyTypeStatic = class MyTypeClass {
    public static staticMethod() { }
    instanceMethod() { }
}

// error: 'instanceMethod' is missing
const MyTypeClass1: MyTypeStatic = class MyTypeClass {
    public static staticMethod() { }
}

// error: 'staticMethod' is missing
const MyTypeClass2: MyTypeStatic = class MyTypeClass {
    instanceMethod() { }
}

The effect is same as in answer with decorators, but without overhead of decorators

Playground

Relevant suggestion/discussion on GitHub


Static modifiers cannot appear on a type member (TypeScript error TS1070). That's why I recommend to use an abstract class to solve the mission:

Example

// Interface definition
abstract class MyInterface {
  static MyName: string;
  abstract getText(): string;
}

// Interface implementation
class MyClass extends MyInterface {
  static MyName = 'TestName';
  getText(): string {
    return `This is my name static name "${MyClass.MyName}".`;
  }
}

// Test run
const test: MyInterface = new MyClass();
console.log(test.getText());

If you're looking to define a static class (ie. all methods/properties are static), you can do something like this:

interface MyStaticClassInterface {
  foo():string;
}

var myStaticClass:MyStaticClassInterface = {
  foo() {
    return 'bar';
  }
};

In this case, the static "class" is really just a plain-ol'-js-object, which implements all the methods of MyStaticClassInterface


Static properties are usually placed on the (global) constructor for the object, whereas the "interface" keyword applies to instances of the object.

The previous answer given is of course correct if you are writing the class in TypeScript. It may help others to know that if you are describing an object that is already implemented elsewhere, then the global constructor including static properties can be declared like this:

declare var myInterface : {
  new(): Interface;
  Name:string;
}

Follow @Duncan's @Bartvds's answer, here to provide a workable way after years passed.

At this point after Typescript 1.5 released (@Jun 15 '15), your helpful interface

interface MyType {
    instanceMethod();
}

interface MyTypeStatic {
    new():MyType;
    staticMethod();
}

can be implemented this way with the help of decorator.

/* class decorator */
function staticImplements<T>() {
    return <U extends T>(constructor: U) => {constructor};
}

@staticImplements<MyTypeStatic>()   /* this statement implements both normal interface & static interface */
class MyTypeClass { /* implements MyType { */ /* so this become optional not required */
    public static staticMethod() {}
    instanceMethod() {}
}

Refer to my comment at github issue 13462.

visual result: Compile error with a hint of static method missing. enter image description here

After static method implemented, hint for method missing. enter image description here

Compilation passed after both static interface and normal interface fulfilled. enter image description here