Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

TypeScript declares how the file works


May 07, 2021 TypeScript


Table of contents


TypeScript declares how the file works

Statement file principle: in-depth exploration

It is difficult to organize modules to provide the APIs you want to be consistent. For example, you might want a module that can create different types with or new expose different naming types at different levels, and have some properties on the module object.

After reading this designation, you'll learn that if you write complex claims files that expose friendly APIs. This is specified for module (UMD) libraries because their choices have higher variability.

Core concepts

If you understand some of the core concepts about how TypeScript works, you can write declaration files for any structure.

Type

If you're reading this guide, you probably know what type of type means in TypeScript. To be clear, the type is introduced by:

  • Type alias declaration type sn = number | string;
  • Interface declaration interface I { x: number[]; }
  • Class Declarations class C { }
  • Enumerant enum E { A, B, C }
  • Point to a type import declaration

Each of these declarations creates a new type name.

Value

You may already understand what a value is compared to a type. A value is a runtime name that can be referenced in an expression. F or let x = 5; Create a value x x.

Similarly, you can create values in the following ways:

  • let const and var declarations
  • Namespace or namespace module value
  • enum statement
  • class declaration
  • The import declaration that points import the value
  • function declaration

Namespace

Types can exist in the namespace. For example, if there let x: A.B.C we think that the C type comes from A.B namespace of A.

This distinction is subtle but important -- here, A.B a required type or value.

Simple combination: one name, multiple meanings

Given a name A we can find three different meanings: a type, a value, or a namespace. H ow the name is parsed depends on what context it is in. F or example, in the let m: A.A = A; A A first used as a namespace, then as a type name, and finally as a value. These meanings may end up pointing to completely different statements!

It may seem confusing, but it's convenient as long as we don't overload it too much. Let's take a look at some useful combination behaviors.

Built-in combinations

Sharp-eyed readers may notice, for example, class in both the type and value lists. class C { } creates two things: type C points to C instance structure of the class, and value C points C to the class constructor. Enumeral declarations have similar behavior.

The user mix

Let's say we wrote foo.d.ts :

export var SomeVar: { a: SomeType };
export interface SomeType {
  count: number;
}

Use it this way:

import * as foo from './foo';
let x: foo.SomeType = foo.SomeVar.a;
console.log(x.count);

It works well, but we know SomeType SomeVar so we want them to have the same name. We can use a combination to represent these two Bar objects (values and objects) by the same name Bar:

export var Bar: { a: Bar };
export interface Bar {
  count: number;
}

This provides an opportunity to understand the use of the structure:

import { Bar } from './foo';
let x: Bar = Bar.a;
console.log(x.count);

Again, here we use Bar the type and value. Note that we did Bar the Bar value to Bar type -- they are independent.

Advanced combinations

There are some claims that can be combined through multiple claims. For example, class C { } interface C s can interface C { } at the same time and can both be properties of C

It is legal as long as there is no conflict. A common rule is that values always conflict with other values with the same name unless they are in different namespaces, and type conflicts occur in cases where type s = string and the namespace never conflicts.

Let's see how to use it.

Add interface

We can use one interface to add additional interface another interface declaration:

interface Foo {
  x: number;
}
// ... elsewhere ...
interface Foo {
  y: number;
}
let a: Foo = ...;
console.log(a.x + a.y); // OK

This also applies to classes:

class Foo {
  x: number;
}
// ... elsewhere ...
interface Foo {
  y: number;
}
let a: Foo = ...;
console.log(a.x + a.y); // OK

Note that we can't use the interface to add members to the type type s = string;

Add namespace

namespace can be used to add new types, values, and namespaces as long as there are no conflicts.

For example, we might add static members to a class:

class C {
}
// ... elsewhere ...
namespace C {
  export let x: number;
}
let y = C.x; // OK

Note that in this example, we add a value to C part of C (its constructor). Here because we added a value, and the container for the other values is another value (the type is contained in the namespace, and the namespace is contained in another namespace).

We can also add a namespace type to the class:

class C {
}
// ... elsewhere ...
namespace C {
  export interface D { }
}
let y: C.D; // OK

In this example, namespace namespace we wrote the namespace C C as a namespace C not conflict with the value C or C C the class.

Finally, we can make different merges through namespace F inally, we could perform many different merges using namespace declarations. This isn't a particularly realistic example, but shows all sorts of interesting behavior:

namespace X {
  export interface Y { }
  export class Z { }
}

// ... elsewhere ...
namespace X {
  export var Y: number;
  export namespace Z {
    export class C { }
  }
}
type X = string;

In this example, the first block of code creates the following name and meaning:

  • A value X namespace declaration contains a value, Z
  • A namespace X namespace declaration contains a value, Z
  • Type Y X Y
  • Type Z in X (instance structure of class)
  • A X value of value Z (the constructor of the class)

The second block of code creates the following names and meanings:

  • The Y number which is a X of the value X
  • A namespace Z
  • The Z which is X of the value X
  • Type X.Z C
  • A X.Z of C for the value C
  • Type X

Use export = or import

An important principle is that export and import export or import all meanings of the target.