Declarations are typescript’s type language that describes the types of variables, functions, and modules provided by the library. Javascript has no type, and many existing libraries are developed in javascript. How to know the corresponding type when using typescript to reference such libraries is through declaration files. There are three key points:

  • Declaration file format: [filename].d.ts.

  • It essentially acts as a middleman, providing type specifications for javascript

  • Some projects are developed directly in typescript, while others use declaration files to plan type design, separating type declaration from business logic

    Focusing only on type design when designing a type is purely declarative, giving typescript absolute abstraction and no attention to implementation details is a great aid to team collaboration.

Whether you’re providing a type specification for javascript or designing it as a type, it’s essentially the same, just the purpose of use.

The statement reference

Some commonly used data formats (e.g. object methods/properties, functions), let’s look at their declaration file writing.

Object property method

// Provide methods/attributes on an object
export const obj = {
  getGreeting(str) {
    return `hello ${str}`;
  },
  count: 10};/** * Declare namespace to describe the type or value accessed by the dot. * / 
declare namespace myLib {
  function getGreeting(srt: string) :string;
  let count: number;
}
Copy the code

Function overloading

function getTypeList(input) {
  if (typeof input === "string") {
    return `hello world of ${input}`;
  } else if (typeof input === "number") {
    return[input]; }}Function overloading: the function name is the same, the argument is different, the return type is different */
declare function getTypeList(str: string) :string;
declare function getTypeList(num: number) :number[];

Copy the code

Tissue types

When you have a large library, you want to think about splitting it up into different namespaces, different interfaces based on responsibilities; This reduces complexity and facilitates maintenance.

// Use namespaces to organize types into different interfaces

/ statement written in the * * * * commodity classification, we list the two classes, in the same namespace, with no interface to declare * /

declare namespace Production {
  / / computer
  interface Computer {
    / / kernel number
    core: number;
    / / size
    size: string;
  }
  / / fruit
  interface Apple {
    / / unit price
    price: number; }}// Also supports nested namespaces, accessed via dots
declare namespace Production.Fruit {
  interface Banana {}
  interface Orange {}
}
Copy the code

Declaration of a class

// Class on business logic
class Greeting {
  word = "";
  constructor(str: string) {
    this.word = str;
  }
  echo(str: string) {
    console.log(str || this.word); }}Constructor, method, attribute declaration */
declare class Greeting {
  constructor(str: string);
  word: string;
  echo(str: string) :void;
}
Copy the code

The global variable

var globalVar = 'hello world'

/** ** ** /
declare var globalVar: string;
Copy the code

Global function

// in the global scope
var greet = (str) = > console.log(str); =/** ** ** /
declare function greet(greeting: string) :void;
Copy the code

Declare is used globally, and namespace is used locally to prevent conflicts. It can be used as required.

Library structure analysis

When writing a declaration file for a JavaScript library, we should first determine the type of the library, whether it is commonJS, ES module, or global class library, UMD Y library. They all have some main characteristics, which we can analyze at the following code level:

  1. Without an explicit reference, use require or define directly anywhere
  2. Use import * as a from ‘b’; Or export c.
  3. Exports or module.exports assigns a value
  4. Assign directly to the window or global object,

Identify modular libraries

It is mainly a function, a class class, commonJS, ES module, files are given the corresponding template. The declaration reference in front of the parameter, written on the basis of understanding, is relatively simple.

  • Var fs = require(“fs”);
  • Documentation describing how to require or import a library
  • Exports or module.exports assigns a value
  • Use import * as a from ‘b’; Or export c.

See the global library

The global library can take some clues from the keywords declared on the call:

  • Top-level VAR statement or function declaration
  • Call window.someName, directly from anywhere
  • DOM primitives like the assumption that document or Window exist

Identify the global library UMD

In the code, there is an immediate execute function:

(function (root, factory) {
    if (typeof define === "function" && define.amd) {
        define(["libName"], factory);
    } else if (typeof module= = ="object" && module.exports) {
        module.exports = factory(require("libName"));
    } else {
        root.returnExports = factory(root.libName);
    }
}(this.function (b) {
Copy the code

Declare file dependencies

A declaration file depends on other declaration files, which can be imported differently depending on the class library

Dependencies on global libraries

If your library depends on the global library, use the /// directive

/// <reference types="someLib" />
function getThing() :someLib.thing;
Copy the code

Dependency on modules

If your library depends on a standard ES module, use the following import statement:

import * as moment from "moment";

function getThing() :moment;
Copy the code

Dependencies on UMD libraries

/// <reference types="moment" />
function getThing() :moment;
Copy the code

ES6 impact on module call signatures

// Namespace import is like import * as moment from "moment" const moment = require("moment")
The ES6 module specification states that the namespace import (import * as x) can only be an object and cannot be executed
import exp = require("express");
var app = exp();
Copy the code

In es6-compliant module loaders, top-level objects (imported here as exp) can only have properties; Top-level module objects can never be called.

Opening esModuleInterop solves both of these problems in TypeScript translated code.

  • The first one changed the behavior of the compiler,
  • The second is fixed with two new helper functions that provide a shim to ensure compatibility of emitted JavaScript:

Links to templates

  • The module
  • Modules: plug-ins
  • Class module:
  • Modules: functions
  • Global class library

Abstract ability

Typescipte’s abstraction capability comes in handy when a new requirement is clarified and the business is usually abstracted. Some of the requirements are not specified yet, and some of the interface fields that depend on the background are still being discussed, but development is already underway. Design business modules, abstract classes, abstract parameters

interface LoginResponse {
  userId: number;
  name: string;
}

interface LoginParams {
  name: string;
  pwd: string;
}

abstract class AbstractLogin {
  / / login
  abstract login(params: LoginParams): Promise<LoginResponse>;
  / / logout
  abstract logout(): Promise<boolean>;
}

* this is an important ability to focus on a point first, and the rest can be dealt with later
export class LoginUser implements AbstractLogin {
  login(params: LoginParams) {
    // do something, without going into details, actually call the background login interface
    console.log(params);
    return Promise.resolve({ userId: 1.name: "hello world" });
  }
  logout() {
    // Implementation details: such as empty token, call to background interface logout, permission logout
    // We can shelve it, we can provide it later, or someone else can implement it
    // Reduce maintenance costs
    return Promise.resolve(true); }}Copy the code

conclusion

When deciding to write a declaration file for a library, the first step is to identify the library based on its characteristics, and then find the corresponding module to refer to. Of course, if you know how to make a statement, it’s better to just organize it. In fact, many third libraries provide declarative files. Nowadays, writing declarative files is more about type design, providing business abstraction for developers.

If there are any mistakes or omissions in this article, please correct them. Thank you.