Home > Software engineering >  What is this TypeScript pattern with interface and declare var?
What is this TypeScript pattern with interface and declare var?

Time:03-10

Looking at this as an example:

interface DOMPoint extends DOMPointReadOnly {
    w: number;
    x: number;
    y: number;
    z: number;
}

declare var DOMPoint: {
    prototype: DOMPoint;
    new(x?: number, y?: number, z?: number, w?: number): DOMPoint;
    fromPoint(other?: DOMPointInit): DOMPoint;
};

interface DOMPointReadOnly {
    readonly w: number;
    readonly x: number;
    readonly y: number;
    readonly z: number;
    matrixTransform(matrix?: DOMMatrixInit): DOMPoint;
    toJSON(): any;
}

declare var DOMPointReadOnly: {
    prototype: DOMPointReadOnly;
    new(x?: number, y?: number, z?: number, w?: number): DOMPointReadOnly;
    fromPoint(other?: DOMPointInit): DOMPointReadOnly;
};

interface DOMQuad {
    readonly p1: DOMPoint;
    readonly p2: DOMPoint;
    readonly p3: DOMPoint;
    readonly p4: DOMPoint;
    getBounds(): DOMRect;
    toJSON(): any;
}

Why are they declaring an uppercase variable the same name as the interface, with a different structure? What does it mean? And in the DOMQuad when they reference DOMPoint, are they referencing the var or the interface? What is the purpose of the var?

CodePudding user response:

It's providing type information for the built-in DOMPoint class provided by the browser.

Why are they declaring an uppercase variable the same name as the interface, with a different structure?

The interface defines what instances of DOMPoint look like. The declare global var DOMPoint tells TypeScript that a global exists (provided by the browser) that is a function that creates DOMPoint instances (new) and a fromPoint static method.

This mimics what TypeScript does with class X { }, where it both creates a type (X) for what instances of X will look like, and a constructor function (X) which is a runtime value (not just a type).

And in the DOMQuad when they reference DOMPoint, are they referencing the var or the interface?

The interface.

What is the purpose of the var?

Purely to tell TypeScript it exists. It doesn't create it (the browser does), it's just so TypeScript knows that using DOMPoint is valid, it's a global that exists with the given signature.

CodePudding user response:

Types and values can have identical names. They aren't necessarily connected.

type A = string
const A = 123

const test: A = A // Type 'number' is not assignable to type 'string'.(2322)

See playground


One case where this comes into play often is classes.

class A {
  static fromX(x: number) {
    const instance = new A()
    instance.x = x
    return instance
  }
  x: number
}

In that snippet, an interface named A is implicitly created that defines the type of instances of the A class. But the value A is that of the class constructor, which has a totally different interface.

For instance:

const obj: A = { x: 123 } // fine

Here obj has all the properties that an instance of A would have, so it's the correct type and all is well. The static method fromX isn't on type A because it's not on the instances of A, it's on the constructor.

In fact, you can see the constructor has a very different type:

type AConstructor = typeof A
type fromXStaticMethod = AConstructor['fromX']
// type fromXStaticMethod = (x: number) => A

Playground

So that's more or less what's being modeled here.


interface DOMPoint extends DOMPointReadOnly {
    w: number;
    x: number;
    y: number;
    z: number;
}

declare var DOMPoint: {
    prototype: DOMPoint;
    new(x?: number, y?: number, z?: number, w?: number): DOMPoint;
    fromPoint(other?: DOMPointInit): DOMPoint;
};

Here the interface DOMPoint is the type of instances, and the value DOMPoint is the constructor. So you can, for example, call DOMPoint.fromPoint() and get an instance of DOMPoint that has w,x,y,z properties.


interface DOMQuad {
    readonly p1: DOMPoint;
    readonly p2: DOMPoint;
    readonly p3: DOMPoint;
    readonly p4: DOMPoint;
    getBounds(): DOMRect;
    toJSON(): any;
}

Here a DOMQuad instance has four points, and each point is a prop that is a DOMPoint instance.

  • Related