Самое полное руководство по изучению TypeScript

внешний интерфейс JavaScript TypeScript
Самое полное руководство по изучению TypeScript

предисловие

Всем привет, я Братец Акула, на этот раз я приношу вам то, что раньше так не любил,Не могу отложитьизТС технологияХа-ха, вы могли заметить, что Brother Shark раньше в основном базировался на стеке технологий Vue, и поскольку сочетание Vue2 и TS не очень гладкое, я решил убрать TS при выборе технологии (на самом деле, я думаю, что он используется Это так же раздражает, как и мой самый ненавистный эслинт.сообщить об ошибкеНеприятно) но Brother Shark в этом году перешел в новую компанию и начал новуюreact hook+tsЭтот набор штампов действительно верен после повторного изучения и использования ts в проектедействительно ладанХа-ха, самое интуитивное чувство состоит в том, что это может помочь нам избежать многих ошибок типа, более дружественных советов и даже некоторых методов, мы, вероятно, можем знать, что функция основана на определенном типе (устраните проблему написания комментариев). Кроме того, это сейчас очень популярен.Vue3Он также подвергся рефакторингу с помощью TS, и комбинация react и ts не упоминается, поэтому студенты, которые еще не начали использовать ts, теперь могут начать обучение с Shark.СвязьПрисоединяйтесь к фронтенд-группе Brother Shark, заходите внутрь, обсуждайте технологии, трогайте рыбу, просите о помощи

Это непросто организовать. Если эта статья окажется вам полезной, помнитеКак СанлианБольшое спасибо!


1 Установка и компиляция ТС

  • Первый шаг — создать пустую папку для изучения ts.
  • Второй шаг — глобально установить ts и ts-node.
cnpm i typescript -g //全局安装ts
cnpm i -g ts-node //全局安装ts-node
  • Третий шаг — создать файл конфигурации tsconfig.js.
tsc --init

Сначала мы будем следовать автоматически сгенерированным элементам конфигурации tsconfig, чтобы использовать конфигурацию внутри.Мы можем сначала проигнорировать его, а затем настроить его, когда мы будем опытными в будущем.

  • Шаг 4 Создайте новый под проектомindex.tsнаписать напрямую
const a: string = "hello";
console.log(a);
  • Пятый шаг компилирует ts в js Введите команду в консоли (терминале)
tsc index.ts

Произошло волшебство, под проектом появился одноименный файл index.js, пока что мы можем скомпилировать файл ts в файл js.

Но умные друзья здесь узнают, что мы установили его глобальноts-nodeЧто он делает?На самом деле этот пакет помогает нам выполнять ts-код напрямую, не компилируя в js.Например, мы набираем в консоли

ts-node index.ts

Вы можете увидеть, что мы напечаталиhelloуже выведено

Тогда могут быть другие друзья, которые найдут, что мы должны вручную выполнить компиляцию каждый раз, когда мы вносим изменения, которые очень неприятно. На самом деле, мы можем добавить параметр для достижения каждого изменения файла TS помощи намавтоматически компилируется в jsЭффект

tsc --watch index.ts

Ладно, среда установлена, идем изучать ядро ​​ts

2 типа ТС

2.1 Логический тип (boolean)
const flag: boolean = true;
2.2 Тип номера
const flag: number = 1;
2.3 Тип строки
const flag: string = "hello";
2.4 Типы врач

Используя перечисления, мы можем хорошо описать некоторые конкретные бизнес-сценарии, такие как весна, лето, осень и зима года, а также каждую неделю с понедельника по воскресенье, а также различные цвета, и мы можем использовать это для описания некоторых информация о состоянии, такая как коды ошибок и т. д.

// 普通枚举 初始值默认为 0 其余的成员会会按顺序自动增长 可以理解为数组下标
enum Color {
  RED,
  PINK,
  BLUE,
}

const pink: Color = Color.PINK;
console.log(pink); // 1

// 设置初始值
enum Color {
  RED = 10,
  PINK,
  BLUE,
}
const pink: Color = Color.PINK;
console.log(pink); // 11

// 字符串枚举 每个都需要声明
enum Color {
  RED = "红色",
  PINK = "粉色",
  BLUE = "蓝色",
}

const pink: Color = Color.PINK;
console.log(pink); // 粉色

// 常量枚举 它是使用 const 关键字修饰的枚举,常量枚举与普通枚举的区别是,整个枚举会在编译阶段被删除 我们可以看下编译之后的效果

const enum Color {
  RED,
  PINK,
  BLUE,
}

const color: Color[] = [Color.RED, Color.PINK, Color.BLUE];

//编译之后的js如下:
var color = [0 /* RED */, 1 /* PINK */, 2 /* BLUE */];
// 可以看到我们的枚举并没有被编译成js代码 只是把color这个数组变量编译出来了
2.5 Тип массива (массив)
const flag1: number[] = [1, 2, 3];
const flag2: Array<number> = [1, 2, 3];
2.6 Тип кортежа (кортеж)

В основных типах TypeScript кортеж представляет известнуюколичествоа такжеТипыНа самом деле можно понять, что он представляет собой особый вид массива

const flag: [string, number] = ["hello", 1];
2.7 Symbol

Когда мы используем Symbol, мы должны добавить вспомогательную библиотеку компиляции es6. должен быть в tsconfig.jsonlibsполе плюсES2015Значение Symbol является единственной константой

const sym1 = Symbol("hello");
const sym2 = Symbol("hello");
console.log(Symbol("hello") === Symbol("hello"));
2.8 Любой тип (любой)

Любой тип можно классифицировать какanyтип, который позволяетanyТип становится типом верхнего уровня системы типов (также известным как глобальный супертип). TypeScript позволяет намanyзначение типа выполняет любую операцию без предварительной проверки

Общие сценарии использования: Может использоваться, когда сторонняя библиотека не предоставляет файл типаanyСложность преобразования типов или структура данных слишком сложны для определения Но не будь слишком зависимымanyВ противном случае он теряет смысл ts

const flag: any = document.getElementById("root");
2.9 нулевой и неопределенный

undefinedа такжеnullОба имеют свои типыundefinedа такжеnull

let u: undefined = undefined;
let n: null = null;
2.10 Неизвестные типы

unknownа такжеanyОсновное отличиеunknownТипы будут строжеunknownМы должны выполнить некоторую форму проверки перед выполнением большинства операций над значением типа.anyПеред выполнением операции типа значения у нас нет никакой проверки Все виды можно разделить наunknownноunknownТипы могут быть присвоены толькоanyтип иunknownсам типanyВсе может быть назначено и назначено

let value: unknown;

value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK

let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
2.11 пустые типы

voidУказывает, что нет типа Когда функция не возвращает значение, TS будет думать, что возвращаемое значениеvoidТипы.

function hello(name: string): void {}
2.12 никогда не печатай

neverОбычно указывает на тип, недоступный пользователю, напримерneverТип — это возвращаемый тип функционального выражения или выражения стрелочной функции, которое всегда выдает исключение или вообще никогда не возвращает значение.

function neverReach(): never {
  throw new Error("an error");
}

Мышление: разница между никогда и пустотой void может быть присвоен нулевым и неопределенным типам. never — это тип, который не содержит значения. Функция с возвращаемым типом void работает нормально. Функция с никогда не возвращаемым типом значения не может нормально вернуться, не может завершиться или выдает исключение.

2.13 Тип больших чисел BigInt

использоватьBigIntБольшие целые числа можно безопасно хранить и обрабатывать мы используемBigIntнеобходимо добавить, когдаESNextВспомогательная библиотека компиляции должна находиться в tsconfig.json.libsполе плюсESNextнужно использовать1nнужно"target": "ESNext" numberа такжеBigIntТипы не как не совместимы

const max1 = Number.MAX_SAFE_INTEGER; // 2**53-1
console.log(max1 + 1 === max1 + 2); //true

const max2 = BigInt(Number.MAX_SAFE_INTEGER);
console.log(max2 + 1n === max2 + 2n); //false

let foo: number;
let bar: bigint;
foo = bar; //error
bar = foo; //error
2.14 объект, объекты и типы {}

objectТипы используются для представления непримитивных типов.

let objectCase: object;
objectCase = 1; // error
objectCase = "a"; // error
objectCase = true; // error
objectCase = null; // error
objectCase = undefined; // error
objectCase = {}; // ok

Большой объектПредставляет все типы с помощью методов toString и hasOwnProperty, поэтому все примитивные и непримитивные типы могут быть назначены объекту (в строгом режимеnullа такжеundefinedНе можем)

let ObjectCase: Object;
ObjectCase = 1; // ok
ObjectCase = "a"; // ok
ObjectCase = true; // ok
ObjectCase = null; // error
ObjectCase = undefined; // error
ObjectCase = {}; // ok

{}Пустой большой тип объекта, а также в качестве объекта представляет собой коллекцию оригинального типа и не примитивных типов

let simpleCase: {};
simpleCase = 1; // ok
simpleCase = "a"; // ok
simpleCase = true; // ok
simpleCase = null; // error
simpleCase = undefined; // error
simpleCase = {}; // ok
2.15 Вывод типа

Относится к способности языка программирования автоматически определять тип значения. Это функция, которая появляется в некоторых строго статически типизированных языках. Если ему не присвоено значение во время определения, оно будет выведено какanyТипы Вы можете использовать вывод типа, если присваиваете значение при его определении.

let flag; //推断为any
let count = 123; //为number类型
let hello = "hello"; //为string类型
2.16 Типы союзов

Типы объединения указывают, что значение может быть одним из многих типов. Когда он не назначен, в типе объединения можно получить доступ только к свойствам и методам, общим для обоих типов.

let name: string | number;
console.log(name.toString());
name = 1;
console.log(name.toFixed(2));
name = "hello";
console.log(name.length);
2.17 Утверждение типа

Иногда вы столкнетесь с ситуацией, когда вы знаете больше деталей о значении, чем TypeScript. Обычно это происходит, когда вы четко знаете, что сущность имеет более точный тип, чем ее существующий тип. На самом деле вам нужно вручную указать ts компилировать в соответствии с типом, который вы указали (этот трюк очень важен и иногда может помочь вам решить многие ошибки компиляции).

Утверждения типов бывают двух видов:

// 尖括号 语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;

// as 语法
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

Хотя между двумя вышеуказанными методами нет разницы, формат угловых скобок вызовет синтаксический конфликт с JSX в реакции, поэтому мы предпочитаем использовать синтаксис as.

ненулевое утверждениеНовый оператор постфиксного выражения ! может использоваться для утверждения, что операнд не находится в контексте, когда средство проверки типов не может определить тип.nullи неundefinedТипы

let flag: null | undefined | string;
flag!.toString(); // ok
flag.toString(); // error
2.18 Литеральный тип

В TypeScript текстура может представлять не только значения, но и тип, так называемый тип слова. В настоящее время TypeScript поддерживает 3 типа типов размером в слово: строковый тип, цифровой тип для всего слова, логический тип, соответствующее строковое слово, цифровое слово, логическое значение, и тот же тип слова совпадает со своим значением. являются, например:

let flag1: "hello" = "hello";
let flag2: 1 = 1;
let flag3: true = true;
2.19 Псевдонимы типов

Псевдонимы типов используются для присвоения типу нового имени.

type flag = string | number;

function hello(value: flag) {}
2.20 Тип кроссовера

Кросс-тип представляет собой объединение нескольких типов в один тип. С помощью оператора & существующие типы могут быть объединены в один тип, содержащий все требуемые типы характеристик.

type Flag1 = { x: number };
type Flag2 = Flag1 & { y: string };

let flag3: Flag2 = {
  x: 1,
  y: "hello",
  henb,
};
2.21 Защита типа

Охранники типов — это выражения, которые во время компиляции используют информацию о типе, чтобы гарантировать тип переменной в области действия. Основная идея состоит в том, чтобы попытаться обнаружить свойство, метод или прототип, чтобы определить, как обрабатывать значение.

защита типа

function double(input: string | number | boolean) {
  if (typeof input === "string") {
    return input + input;
  } else {
    if (typeof input === "number") {
      return input * 2;
    } else {
      return !input;
    }
  }
}

в ключевом слове

interface Bird {
  fly: number;
}

interface Dog {
  leg: number;
}

function getNumber(value: Bird | Dog) {
  if ("fly" in value) {
    return value.fly;
  }
  return value.leg;
}

защита типа instanceof

class Animal {
  name!: string;
}
class Bird extends Animal {
  fly!: number;
}
function getName(animal: Animal) {
  if (animal instanceof Bird) {
    console.log(animal.fly);
  } else {
    console.log(animal.name);
  }
}

защита пользовательского типа

пройти черезtype is xxxтакие предикаты типа для защиты типа

Например следующий примерvalue is objectОн будет думать, что если функция возвращает true, то определенное значение имеет тип object

function isObject(value: unknown): value is object {
  return typeof value === "object" && value !== null;
}

function fn(x: string | object) {
  if (isObject(x)) {
    // ....
  } else {
    // .....
  }
}

3 функции

3.1 Определение функций

Вы можете указать тип параметра и тип возвращаемого значения

function hello(name: string): void {
  console.log("hello", name);
}
hello("hahaha");
3.2 Функциональные выражения

определить тип функции

type SumFunc = (x: number, y: number) => number;

let countNumber: SumFunc = function (a, b) {
  return a + b;
};
3.3 Дополнительные параметры

В ТС формальные параметры и фактические параметры функции должны совпадать, если они не совпадают, необязательные параметры должны быть настроены, и они должны бытьпоследний параметр

function print(name: string, age?: number): void {
  console.log(name, age);
}
print("hahaha");
3.4 Параметры по умолчанию
function ajax(url: string, method: string = "GET") {
  console.log(url, method);
}
ajax("/users");
3.5 Остальные параметры
function sum(...numbers: number[]) {
  return numbers.reduce((val, item) => (val += item), 0);
}
console.log(sum(1, 2, 3));
3.6 Перегрузка функций

Метод перегрузки представляет собой перегруженную функцию или функцию с одинаковым именем и возможностью создания множества различных параметров процесса по количеству или типу. В TypeScript производительность предоставления множества функций одного и того же типа определяется как функция

let obj: any = {};
function attr(val: string): void;
function attr(val: number): void;
function attr(val: any): void {
  if (typeof val === "string") {
    obj.name = val;
  } else {
    obj.age = val;
  }
}
attr("hahaha");
attr(9);
attr(true);
console.log(obj);

Примечание. Перегрузка реального выполнения тела функции - это последняя определенная функция с тем же именем, все относятся к типу функции, определенной до того, как последнее тело определения функции не может написать конкретную функцию, может определить тип реализации.

Категория 4

4.1 Определение класса

В TypeScript мы можем передатьClassключевое слово для определения класса

class Person {
  name!: string; //如果初始属性没赋值就需要加上!
  constructor(_name: string) {
    this.name = _name;
  }
  getName(): void {
    console.log(this.name);
  }
}
let p1 = new Person("hello");
p1.getName();

Конечно, если мы хотим избавить себя от проблем, мы также можем записать определение атрибута прямо в параметры конструктора (но это обычно не рекомендуется, потому что это сделает код более трудным для чтения).

class Person {
  constructor(public name: string) {}
  getName(): void {
    console.log(this.name);
  }
}
let p1 = new Person("hello");
p1.getName();

Примечание. Когда мы определяем класс, вы получите2 типаОдин из них — тип функции типа конструктора (как тип обычного конструктора). Другой тип экземпляра класса (представляющий экземпляр)

см. пример

class Component {
  static myName: string = "静态名称属性";
  myName: string = "实例名称属性";
}
//ts 一个类型 一个叫值
//放在=后面的是值
let com = Component; //这里是代表构造函数
//冒号后面的是类型
let c: Component = new Component(); //这里是代表实例类型
let f: typeof Component = com;
4.2 Аксессуар

В TypeScript мы можем использовать средства доступа для изменения поведения чтения и назначения свойств в классе.

class User {
  myname: string;
  constructor(myname: string) {
    this.myname = myname;
  }
  get name() {
    return this.myname;
  }
  set name(value) {
    this.myname = value;
  }
}

let user = new User("hello");
user.name = "world";
console.log(user.name);

На самом деле мы можем посмотреть код переведенный на es5 Принцип очень простой, достаточно использовать Object.defineProperty перехватывает методы get и set, соответствующие свойству прототипа класса.

var User = /** @class */ (function () {
  function User(myname) {
    this.myname = myname;
  }
  Object.defineProperty(User.prototype, "name", {
    get: function () {
      return this.myname;
    },
    set: function (value) {
      this.myname = value;
    },
    enumerable: false,
    configurable: true,
  });
  return User;
})();
var user = new User("hello");
user.name = "world";
console.log(user.name);
4.3 readonly свойство только для чтения

Переменные, измененные только для чтения, могут использоваться только вКонструкторинициализирован в Система типов TypeScript также позволяет помечать свойства интерфейса, типа и класса как доступные только для чтения. readonly просто выполняет проверку кода на этапе компиляции.

class Animal {
  public readonly name: string;
  constructor(name: string) {
    this.name = name;
  }
  changeName(name: string) {
    this.name = name; //这个ts是报错的
  }
}

let a = new Animal("hello");
4.4 Наследование

После того, как подкласс наследует родительский класс, экземпляр подкласса имеет свойства и методы родительского класса, что может повысить возможность повторного использования кода.

Абстрагируйте общие методы подклассов и поместите их в родительский класс, а также поместите свою собственную специальную логику в подкласс, чтобы переопределить логику родительского класса.

super может вызывать методы и свойства родительского класса

В Teadescript мы можем достичь с помощью наследования расширяет ключевое слово

class Person {
  name: string; //定义实例的属性,默认省略public修饰符
  age: number;
  constructor(name: string, age: number) {
    //构造函数
    this.name = name;
    this.age = age;
  }
  getName(): string {
    return this.name;
  }
  setName(name: string): void {
    this.name = name;
  }
}
class Student extends Person {
  no: number;
  constructor(name: string, age: number, no: number) {
    super(name, age);
    this.no = no;
  }
  getNo(): number {
    return this.no;
  }
}
let s1 = new Student("hello", 10, 1);
console.log(s1);
4.5 Модификаторы в классах

publicВнутри класса подклассы могут быть доступны в любом другом месте.protectedДоступ к подклассам в классе возможен, но не где-либо ещеprivateДоступ к нему можно получить внутри класса, но не в подклассах и где-либо еще

class Parent {
  public name: string;
  protected age: number;
  private car: number;
  constructor(name: string, age: number, car: number) {
    //构造函数
    this.name = name;
    this.age = age;
    this.car = car;
  }
  getName(): string {
    return this.name;
  }
  setName(name: string): void {
    this.name = name;
  }
}
class Child extends Parent {
  constructor(name: string, age: number, car: number) {
    super(name, age, car);
  }
  desc() {
    console.log(`${this.name} ${this.age} ${this.car}`); //car访问不到 会报错
  }
}

let child = new Child("hello", 10, 1000);
console.log(child.name);
console.log(child.age); //age访问不到 会报错
console.log(child.car); //car访问不到 会报错
4.6 Статические свойства Статические методы

Статические свойства и методы класса определяются непосредственно в самом классе, поэтому доступ к ним можно получить только путем прямого вызова методов и свойств класса.

class Parent {
  static mainName = "Parent";
  static getmainName() {
    console.log(this); //注意静态方法里面的this指向的是类本身 而不是类的实例对象 所以静态方法里面只能访问类的静态属性和方法
    return this.mainName;
  }
  public name: string;
  constructor(name: string) {
    //构造函数
    this.name = name;
  }
}
console.log(Parent.mainName);
console.log(Parent.getmainName());
4.7 Абстрактные классы и абстрактные методы

Абстрактные классы не могут быть созданы, могут только наследоваться и не могут создавать экземпляры абстрактных классов. Подклассы могут реализовывать различные абстрактные классы

Абстрактные методы могут появляться только в абстрактных классах, а абстрактные методы не могут быть конкретно реализованы в абстрактных классах, только в подклассах абстрактных классов (должны быть реализованы)

используемые сцены: Обычно мы используем абстрактные классы и абстрактные методы для извлечения общности вещей.В будущем все унаследованные подклассы должны реализовывать свою собственную специфическую логику в соответствии со спецификацией, что может повысить удобство сопровождения и повторное использование кода.

использоватьabstractКлючевые слова для определения абстрактных классов и абстрактных методов

abstract class Animal {
  name!: string;
  abstract speak(): void;
}
class Cat extends Animal {
  speak() {
    console.log("喵喵喵");
  }
}
let animal = new Animal(); //直接报错 无法创建抽象类的实例
let cat = new Cat();
cat.speak();

Мысль 1: разница между переопределением и перегрузкой

ПереписатьОтносится к подклассу, переопределяющему метод, унаследованный от родительского класса.перегрузкаОтносится к предоставлению нескольких определений типов для одной и той же функции.

class Animal {
  speak(word: string): string {
    return "动物:" + word;
  }
}
class Cat extends Animal {
  speak(word: string): string {
    return "猫:" + word;
  }
}
let cat = new Cat();
console.log(cat.speak("hello"));
// 上面是重写
//--------------------------------------------
// 下面是重载
function double(val: number): number;
function double(val: string): string;
function double(val: any): any {
  if (typeof val == "number") {
    return val * 2;
  }
  return val + val;
}

let r = double(1);
console.log(r);

Мысль 2: Что такоеполиморфизм

Метод определен в родительском классе, а в подклассе есть несколько реализаций.Когда программа запускается, разные операции выполняются в соответствии с разными объектами для достижения привязки во время выполнения.

abstract class Animal {
  // 声明抽象的方法,让子类去实现
  abstract sleep(): void;
}
class Dog extends Animal {
  sleep() {
    console.log("dog sleep");
  }
}
let dog = new Dog();
class Cat extends Animal {
  sleep() {
    console.log("cat sleep");
  }
}
let cat = new Cat();
let animals: Animal[] = [dog, cat];
animals.forEach((i) => {
  i.sleep();
});

5 портов

Интерфейсы могут быть представлены как абстракции поведения в объектно-ориентированном программировании, а также могут использоваться для описания формы объектов.

мы используемinterfaceКлючевые слова для определения интерфейса В интерфейсе вы можете отделить каждый элемент точкой с запятой или запятой, или вы можете ничего не добавлять

5.1 Форма объектов
//接口可以用来描述`对象的形状`
//接口可以用来描述`对象的形状`
interface Speakable {
  speak(): void;
  readonly lng: string; //readonly表示只读属性 后续不可以更改
  name?: string; //?表示可选属性
}

let speakman: Speakable = {
  //   speak() {}, //少属性会报错
  name: "hello",
  lng: "en",
  age: 111, //多属性也会报错
};
5.2 Поведенческая абстракция

Интерфейс может абстрагировать свойства и методы, общие для некоторых классов, и может использоваться для ограничения классов, реализующих этот интерфейс.

Класс может реализовать несколько интерфейсов, один интерфейс может быть реализован как множество классов

мы используемimplementsключевое слово для представления реализации

//接口可以在面向对象编程中表示为行为的抽象
interface Speakable {
  speak(): void;
}
interface Eatable {
  eat(): void;
}
//一个类可以实现多个接口
class Person implements Speakable, Eatable {
  speak() {
    console.log("Person说话");
  }
  //   eat() {} //需要实现的接口包含eat方法 不实现会报错
}
5.3 Определение произвольных свойств

Если мы не можем знать заранее, какие свойства есть, когда мы определяем интерфейс, мы можем использовать[propName:string]:any, имя propName произвольное

interface Person {
  id: number;
  name: string;
  [propName: string]: any;
}

let p1 = {
  id: 1,
  name: "hello",
  age: 10,
};

Этот интерфейс указывает, что должно быть два поля, идентификатор и имя, а затем можно добавить оставшиеся неизвестные поля.

5.4 Наследование интерфейсов

Помимо того, что классы могут наследовать интерфейсы, мы также можем наследовать одно и то же использованиеextendsключевые слова

interface Speakable {
  speak(): void;
}
interface SpeakChinese extends Speakable {
  speakChinese(): void;
}
class Person implements SpeakChinese {
  speak() {
    console.log("Person");
  }
  speakChinese() {
    console.log("speakChinese");
  }
}
5.5 Интерфейс функционального типа

Интерфейсы могут использоваться для определения типов функций.

interface discount {
  (price: number): number;
}
let cost: discount = function (price: number): number {
  return price * 0.8;
};
5.6 Интерфейсы типов для конструкторов

Используйте специальное ключевое слово new() для описания типа конструктора класса.

class Animal {
  constructor(public name: string) {}
}
//不加new是修饰函数的,加new是修饰类的
interface WithNameClass {
  new (name: string): Animal;
}
function createAnimal(clazz: WithNameClass, name: string) {
  return new clazz(name);
}
let a = createAnimal(Animal, "hello");
console.log(a.name);

На самом деле такое использование обычно происходит, когда нам нужно взять класс в качестве параметра, нам нужно ограничить тип конструктора входящего класса, поэтому нам нужно использовать ключевое слово new для представления типа конструктора класса, чтобы отличить его от обычные функции


Мышление: разница между интерфейсами и псевдонимами типов Эта тема классическаяТС вопросы интервью

На самом деле использование интерфейсных типов и псевдонимов типов в большинстве случаев эквивалентно, но в некоторых конкретных случаях между ними все же есть существенные различия.

1. Основные типы данных В отличие от интерфейсов, псевдонимы типов также могут использоваться для других типов, таких как примитивные типы (примитивные значения), типы объединения, кортежи.

// primitive
type Name = string;

// union
type PartialPoint = PartialPointX | PartialPointY;

// tuple
type Data = [number, string];

// dom
let div = document.createElement("div");
type B = typeof div;

2. Повторяющиеся определения

Интерфейсы могут быть определены несколько раз и будут автоматически объединены в один интерфейс Псевдонимы типов не могут быть определены повторно

interface Point {
  x: number;
}
interface Point {
  y: number;
}
const point: Point = { x: 1, y: 2 };

3. Расширение Интерфейсы могут расширять псевдонимы типов, и аналогичным образом псевдонимы типов могут расширять интерфейсы. Но то, как они реализуют расширение, отличается

Расширение интерфейса — это наследование, которое реализуется с помощью расширений. Расширением псевдонима типа является перекрестный тип, который реализуется с помощью &.

// 接口扩展接口
interface PointX {
  x: number;
}

interface Point extends PointX {
  y: number;
}
// ----
// 类型别名扩展类型别名
type PointX = {
  x: number;
};

type Point = PointX & {
  y: number;
};
// ----
// 接口扩展类型别名
type PointX = {
  x: number;
};
interface Point extends PointX {
  y: number;
}
// ----
// 类型别名扩展接口
interface PointX {
  x: number;
}
type Point = PointX & {
  y: number;
};

4. Осознайте Здесь есть особый случай, когда класс не может реализовать псевдоним типа, определяющий тип объединения.

type PartialPoint = { x: number } | { y: number };

// A class can only implement an object type or
// intersection of object types with statically known members.
class SomePartialPoint implements PartialPoint {
  // Error
  x = 1;
  y = 2;
}

6 дженериков

Обобщения относятся к функции, которая не указывает конкретный тип заранее при определении функции, интерфейса или класса, но указывает тип при его использовании.

Чтобы лучше понять роль дженериков, мы можем посмотреть на следующий пример.

function createArray(length: number, value: any): any[] {
  let result = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
}

createArray(3, "x"); // ['x', 'x', 'x']

Приведенный выше код используется для создания массива с длиной длины и значением значения Но на самом деле мы можем найти проблему, независимо от того, какой тип значения мы передаем, массив возвращаемого значения всегда имеет тип any.Если мы хотим получить эффект, заключающийся в том, что мы не знаем, какой тип мы передаем заранее, но мы надеемся, что какой бы тип мы ни передавали в наш Тип возвращаемого массива должен быть таким же, как параметр, тогда на сцену выйдут дженерики

использоватьДженерикиМодернизация

function createArray<T>(length: number, value: T): Array<T> {
  let result: T[] = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
}

createArray<string>(3, "x"); // ['x', 'x', 'x']

Мы можем использовать метод записи , а затем передать переменную T для представления типа, который должна использовать последующая функция.Когда мы фактически вызываем функцию, передача типа T может решить многие проблемы, связанные с типом, который нельзя определить заранее.

6.1 Параметры нескольких типов

Если нам нужно иметь несколько заполнителей неизвестного типа, мы можем определить любые буквы для представления параметров разных типов.

function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]];
}

swap([7, "seven"]); // ['seven', 7]
6.2 Общие ограничения

Когда универсальная переменная используется внутри функции, поскольку заранее неизвестно, какого она типа, ее свойствами или методами нельзя манипулировать по желанию:

function loggingIdentity<T>(arg: T): T {
  console.log(arg.length);
  return arg;
}

// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.

В приведенном выше примере универсальный тип T не обязательно содержит длину свойства, поэтому при компиляции сообщается об ошибке.

На этом этапе мы можем ограничить общий тип, чтобы разрешить функции передавать только те переменные, которые содержат свойство длины. Этообщие ограничения

interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

Примечание: мы используем дженерики внутриextendsКлючевое слово представляет общее ограничение, которое необходимо отличать от наследования класса.

6.3 Общие интерфейсы

Вы также можете указать дженерики при определении интерфейса.

interface Cart<T> {
  list: T[];
}
let cart: Cart<{ name: string; price: number }> = {
  list: [{ name: "hello", price: 10 }],
};
console.log(cart.list[0].name, cart.list[0].price);

После того, как мы определили тип T, переданный интерфейсом, массив объектов, возвращаемый после T, является типом параметра, переданным в это время.

6.4 Общие классы
class MyArray<T> {
  private list: T[] = [];
  add(value: T) {
    this.list.push(value);
  }
  getMax(): T {
    let result = this.list[0];
    for (let i = 0; i < this.list.length; i++) {
      if (this.list[i] > result) {
        result = this.list[i];
      }
    }
    return result;
  }
}
let arr = new MyArray();
arr.add(1);
arr.add(2);
arr.add(3);
let ret = arr.getMax();
console.log(ret);

Пример обращения Мы реализуем универсальный класс, который добавляет числа в массив и получает максимальное значение

6.5 Псевдонимы общего типа
type Cart<T> = { list: T[] } | T[];
let c1: Cart<string> = { list: ["1"] };
let c2: Cart<number> = [1];
6.6 Типы по умолчанию для общих параметров

Мы можем указать типы по умолчанию для параметров типа в дженериках. Этот тип по умолчанию работает, когда дженерики используются без указания параметра типа непосредственно в коде, и его нельзя вывести из фактического параметра значения.

function createArray<T = string>(length: number, value: T): Array<T> {
  let result: T[] = [];
  for (let i = 0; i < length; i++) {
    result[i] = value;
  }
  return result;
}

7 практических советов

7.1 тип ключевых слов

typeofВ дополнение к защите типов ключевые слова также могут наследовать типы от реализаций.

//先定义变量,再定义类型
let p1 = {
  name: "hello",
  age: 10,
  gender: "male",
};
type People = typeof p1;
function getName(p: People): string {
  return p.name;
}
getName(p1);

В приведенном выше примере используется typeof для получения типа переменной.

7.2 ключевые слова

keyofМожет использоваться для получения всех ключевых значений интерфейса объекта.

interface Person {
  name: string;
  age: number;
  gender: "male" | "female";
}
//type PersonKey = 'name'|'age'|'gender';
type PersonKey = keyof Person;

function getValueByKey(p: Person, key: PersonKey) {
  return p[key];
}
let val = getValueByKey({ name: "hello", age: 10, gender: "male" }, "name");
console.log(val);
7.3 Операторы доступа к индексу

Используйте оператор [] для индексации доступа

interface Person {
  name: string;
  age: number;
}

type x = Person["name"]; // x is string
7.4 Тип отображения в

Используйте оператор in для пакетного определения свойств в типе при определении

interface Person {
  name: string;
  age: number;
  gender: "male" | "female";
}
//批量把一个接口中的属性都变成可选的
type PartPerson = {
  [Key in keyof Person]?: Person[Key];
};

let p1: PartPerson = {};
7.5 вывести ключевое слово

В операторе условного типа вы можете использовать infer, чтобы объявить переменную типа и использовать ее.

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

В приведенном выше коде infer R должен объявить переменную для переноса типа возвращаемого значения сигнатуры входящей функции.Проще говоря, он используется для получения типа возвращаемого значения функции для удобства.

7.6 Типы встроенных инструментов
  1. Исключить исключить U из типов, которым T можно присвоить
type Exclude<T, U> = T extends U ? never : T;

type E = Exclude<string | number, string>;
let e: E = 10;
  1. Извлечь извлечь U из типа, которому T присваивается
type Extract<T, U> = T extends U ? T : never;

type E = Extract<string | number, string>;
let e: E = "1";
  1. Обнуляемый исключить из Тnullа такжеundefined
type NonNullable<T> = T extends null | undefined ? never : T;

type E = NonNullable<string | number | null | undefined>;
let e: E = null;
  1. ReturnType inferвпервые появился в этом PR, указанном вextendsПеременная типа, которая будет выводиться в условном операторе
type ReturnType<T extends (...args: any[]) => any> = T extends (
  ...args: any[]
) => infer R
  ? R
  : any;
function getUserInfo() {
  return { name: "hello", age: 10 };
}

// 通过 ReturnType 将 getUserInfo 的返回值类型赋给了 UserInfo
type UserInfo = ReturnType<typeof getUserInfo>;

const userA: UserInfo = {
  name: "hello",
  age: 10,
};

Видно, что тип инструмента в основном предназначен для получения возвращаемого типа типа функции.

  1. Параметры Тип инструмента в основном предназначен для получения типа параметра типа функции.
type Parameters<T> = T extends (...args: infer R) => any ? R : any;

type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<<T>(arg: T) => T>; // [unknown]
  1. Частичный Partial может изменить входящие свойства с необязательных на необязательные.
type Partial<T> = { [P in keyof T]?: T[P] };
interface A {
  a1: string;
  a2: number;
  a3: boolean;
}
type aPartial = Partial<A>;
const a: aPartial = {}; // 不会报错
  1. Необходимый Required может превратить необязательные элементы входящих атрибутов в обязательные элементы, что реализовано здесь с модификатором -?.
interface Person {
  name: string;
  age: number;
  gender?: "male" | "female";
}
/**
 * type Required<T> = { [P in keyof T]-?: T[P] };
 */
let p: Required<Person> = {
  name: "hello",
  age: 10,
  gender: "male",
};
  1. Только для чтения Readonly реализуется путем добавления модификатора readonly к каждому элементу входящего свойства.
interface Person {
  name: string;
  age: number;
  gender?: "male" | "female";
}
//type Readonly<T> = { readonly [P in keyof T]: T[P] };
let p: Readonly<Person> = {
  name: "hello",
  age: 10,
  gender: "male",
};
p.age = 11; //error
  1. Выбрать Pick может помочь нам извлечь некоторую прибыль из входящих свойств.
interface Todo {
  title: string;
  description: string;
  done: boolean;
}
/**
 * From T pick a set of properties K
 * type Pick<T, K extends keyof T> = { [P in K]: T[P] };
 */
type TodoBase = Pick<Todo, "title" | "done">;

// =
type TodoBase = {
  title: string;
  done: boolean;
};
  1. Запись Создает тип, который имеет набор свойств K, каждое из которых относится к типу T. Может использоваться для отображения свойств одного типа на другой. Дженерики, лежащие в основе Record, — это типы ключей и значений объекта.

Простое понимание: K соответствует соответствующему ключу, T соответствует значению объекта, а возвращаемый объект является объявленным объектом. Но общее ограничение, соответствующее K, равноkeyof anyЭто означает, что толькоstring|number|symbol

// type Record<K extends keyof any, T> = {
// [P in K]: T;
// };
type Point = "x" | "y";
type PointList = Record<Point, { value: number }>;
const cars: PointList = {
  x: { value: 10 },
  y: { value: 20 },
};
  1. Опустить Отбор атрибутов на основе объявленных типов для получения новых типов
// type Omit=Pick<T,Exclude<keyof T,K>>
type User = {
id: string;
name: string;
email: string;
};
type UserWithoutEmail = Omit<User, "email">;// UserWithoutEmail ={id: string;name: string;}
};

8 декораторов TypeScript

Декоратор — это специальный тип объявления, который можно присоединить к объявлению класса, методу, свойству или параметру, чтобы изменить поведение класса.

Общие декораторы включают декораторы классов, декораторы свойств, декораторы методов и декораторы параметров.

Метод письма декоратора делится на обычный декоратор и фабрику декораторов.

Метод записи с использованием декоратора @ должен поместить tsconfig.jsonexperimentalDecoratorsполе установлено в true

8.1 Декораторы классов

Декораторы класса объявляются перед объявлением класса и используются для мониторинга, изменения или замены определения класса.

namespace a {
  //当装饰器作为修饰类的时候,会把构造器传递进去
  function addNameEat(constructor: Function) {
    constructor.prototype.name = "hello";
    constructor.prototype.eat = function () {
      console.log("eat");
    };
  }
  @addNameEat
  class Person {
    name!: string;
    eat!: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name);
  p.eat();
}

namespace b {
  //还可以使用装饰器工厂 这样可以传递额外参数
  function addNameEatFactory(name: string) {
    return function (constructor: Function) {
      constructor.prototype.name = name;
      constructor.prototype.eat = function () {
        console.log("eat");
      };
    };
  }
  @addNameEatFactory("hello")
  class Person {
    name!: string;
    eat!: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name);
  p.eat();
}

namespace c {
  //还可以替换类,不过替换的类要与原类结构相同
  function enhancer(constructor: Function) {
    return class {
      name: string = "jiagou";
      eat() {
        console.log("吃饭饭");
      }
    };
  }
  @enhancer
  class Person {
    name!: string;
    eat!: Function;
    constructor() {}
  }
  let p: Person = new Person();
  console.log(p.name);
  p.eat();
}
8.2 Декораторы свойств

Выражение декоратора свойства будет вызываться во время выполнения как функция, передавая 2 аргумента. Первый параметр — это конструктор класса для статических членов и объект-прототип класса для членов-экземпляров. Второй параметр - это имя свойства

//修饰实例属性
function upperCase(target: any, propertyKey: string) {
  let value = target[propertyKey];
  const getter = function () {
    return value;
  };
  // 用来替换的setter
  const setter = function (newVal: string) {
    value = newVal.toUpperCase();
  };
  // 替换属性,先删除原先的属性,再重新定义属性
  if (delete target[propertyKey]) {
    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true,
    });
  }
}

class Person {
  @upperCase
  name!: string;
}
let p: Person = new Person();
p.name = "world";
console.log(p.name);
8.3 Декораторы методов

Декораторы методов, как следует из названия, используются для оформления методов класса. Он принимает три параметра: target: Object — конструктор класса для статических членов или объект-прототип класса для членов-экземпляров. propertyKey: string | symbol — имя метода descriptor: TypePropertyDescript — дескриптор свойства

//修饰实例方法
function noEnumerable(
  target: any,
  property: string,
  descriptor: PropertyDescriptor
) {
  console.log("target.getName", target.getName);
  console.log("target.getAge", target.getAge);
  descriptor.enumerable = false;
}
//重写方法
function toNumber(
  target: any,
  methodName: string,
  descriptor: PropertyDescriptor
) {
  let oldMethod = descriptor.value;
  descriptor.value = function (...args: any[]) {
    args = args.map((item) => parseFloat(item));
    return oldMethod.apply(this, args);
  };
}
class Person {
  name: string = "hello";
  public static age: number = 10;
  constructor() {}
  @noEnumerable
  getName() {
    console.log(this.name);
  }
  @toNumber
  sum(...args: any[]) {
    return args.reduce((accu: number, item: number) => accu + item, 0);
  }
}
let p: Person = new Person();
for (let attr in p) {
  console.log("attr=", attr);
}
p.getName();
console.log(p.sum("1", "2", "3"));
8.4 Декораторы параметров

Декоратор параметров, как следует из названия, используется для оформления параметров функции и получает три параметра:

target: Object - класс, который нужно украсить propertyKey: string | symbol — имя метода параметрИндекс: число - значение индекса параметра в методе

function Log(target: Function, key: string, parameterIndex: number) {
  let functionLogged = key || target.prototype.constructor.name;
  console.log(`The parameter in position ${parameterIndex} at ${functionLogged} has
	been decorated`);
}

class Greeter {
  greeting: string;
  constructor(@Log phrase: string) {
    this.greeting = phrase;
  }
}

После успешного выполнения приведенного выше кода консоль выведет следующие результаты:"The parameter in position 0 at Greeter has been decorated"

8.5 Порядок выполнения декораторов

При наличии нескольких декораторов параметров: выполнять последовательно, начиная с последнего параметра вперед

Сначала выполняются декораторы параметров в методах и параметры методов. Декораторы методов и свойств, в зависимости от того, что наступит раньше, будут выполняться первыми. Поскольку параметр является частью метода, он всегда будет находиться непосредственно рядом с выполнением метода.

Декораторы класса всегда выполняются последними

function Class1Decorator() {
  return function (target: any) {
    console.log("类1装饰器");
  };
}
function Class2Decorator() {
  return function (target: any) {
    console.log("类2装饰器");
  };
}
function MethodDecorator() {
  return function (
    target: any,
    methodName: string,
    descriptor: PropertyDescriptor
  ) {
    console.log("方法装饰器");
  };
}
function Param1Decorator() {
  return function (target: any, methodName: string, paramIndex: number) {
    console.log("参数1装饰器");
  };
}
function Param2Decorator() {
  return function (target: any, methodName: string, paramIndex: number) {
    console.log("参数2装饰器");
  };
}
function PropertyDecorator(name: string) {
  return function (target: any, propertyName: string) {
    console.log(name + "属性装饰器");
  };
}

@Class1Decorator()
@Class2Decorator()
class Person {
  @PropertyDecorator("name")
  name: string = "hello";
  @PropertyDecorator("age")
  age: number = 10;
  @MethodDecorator()
  greet(@Param1Decorator() p1: string, @Param2Decorator() p2: string) {}
}

/**
name属性装饰器
age属性装饰器
参数2装饰器
参数1装饰器
方法装饰器
类2装饰器
类1装饰器
 */

9 Компиляция

9.1 Роль файла tsconfig.json
  • Корневой путь, используемый для идентификации проекта TypeScript;
  • Используется для настройки компилятора TypeScript;
  • Используется для указания скомпилированного файла.
9.2 Важные поля TSConfig.json
  • files — задает имя компилируемых файлов;
  • include — задайте файлы, которые необходимо скомпилировать, поддержите сопоставление с образцом пути;
  • исключить - установить файлы, которые не нужно компилировать, поддерживать сопоставление с образцом пути;
  • compileOptions — установка параметров, связанных с процессом компиляции.
9.3 Параметры компилятораOptions
{
  "compilerOptions": {

    /* 基本选项 */
    "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
    "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
    "lib": [],                             // 指定要包含在编译中的库文件
    "allowJs": true,                       // 允许编译 javascript 文件
    "checkJs": true,                       // 报告 javascript 文件中的错误
    "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
    "declaration": true,                   // 生成相应的 '.d.ts' 文件
    "sourceMap": true,                     // 生成相应的 '.map' 文件
    "outFile": "./",                       // 将输出文件合并为一个文件
    "outDir": "./",                        // 指定输出目录
    "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
    "removeComments": true,                // 删除编译后的所有的注释
    "noEmit": true,                        // 不生成输出文件
    "importHelpers": true,                 // 从 tslib 导入辅助工具函数
    "isolatedModules": true,               // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).

    /* 严格的类型检查选项 */
    "strict": true,                        // 启用所有严格类型检查选项
    "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
    "strictNullChecks": true,              // 启用严格的 null 检查
    "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
    "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'

    /* 额外的检查 */
    "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
    "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
    "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
    "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)

    /* 模块解析选项 */
    "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
    "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
    "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
    "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
    "typeRoots": [],                       // 包含类型声明的文件列表
    "types": [],                           // 需要包含的类型声明文件名列表
    "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。

    /* Source Map Options */
    "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
    "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
    "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
    "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性

    /* 其他选项 */
    "experimentalDecorators": true,        // 启用装饰器
    "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
  }
}

10 модулей и файлов объявлений

10.1 Глобальные модули

По умолчанию, когда вы начинаете писать код в новом файле TypeScript, он находится в глобальном пространстве имен.

Использование глобального пространства переменных опасно, поскольку оно будет конфликтовать с именованием кода в файле. Мы рекомендуем использовать файловые модули, указанные ниже.

foo.ts

const foo = 123;

bar.ts

const bar = foo; // allowed
10.2 Файловый модуль
  • Файловые модули также известны как внешние модули. Если у вас есть импорт или экспорт на корневом уровне вашего файла TypeScript, он создаст локальную область в этом файле.

  • Модуль — это сокращение от внешнего модуля в TS, основное внимание уделяется коду и повторному использованию.

  • Модули выполняются в своей области, а не в глобальной области.

  • Переменные, функции, классы и т. д. в модуле не видны снаружи, если вы не экспортируете его.

  • Если вы хотите использовать переменную, экспортированную в модуль, вам нужно импортировать

foo.ts

const foo = 123;
export {};

bar.ts

const bar = foo; // error
10.3 Файл декларации
  • Мы можем поместить объявления типов в отдельный файл объявлений типов.
  • Соглашение об именах файлов: *.d.ts
  • Просмотр файла объявления типа помогает понять, как используется библиотека.

typings\jquery.d.ts

declare const $: (selector: string) => {
  click(): void;
  width(length: number): void;
};
10.4 Документы-декларации третьих лиц
  • Может устанавливать и использовать сторонние файлы объявлений
  • @types — это условный префикс, все сторонние объявленные библиотеки типов будут иметь этот префикс.
  • В JavaScript есть много встроенных объектов, которые можно рассматривать как объявленные типы в TypeScript.
  • Встроенные объекты — это объекты, существующие в глобальной области видимости (Global) по стандарту. Стандарт здесь относится к стандарту ECMAScript и других сред (например, DOM).
  • Файлы объявлений типов этих встроенных объектов включены в файлы объявлений типов основной библиотеки TypeScript.файл объявления ядра ts
10.5 Поиск файлов объявлений
  • Если это файл декларации, написанный вручную, необходимо выполнить одно из следующих условий, чтобы его можно было правильно идентифицировать.
  • Укажите адрес файла объявления типа для поля типов или типов в package.json.
  • В корневом каталоге проекта напишите файл index.d.ts
  • Для файла записи (файл записи, указанный в основном поле в package.json) напишите файл .d.ts с тем же именем и другим суффиксом.
{
    "name": "myLib",
    "version": "1.0.0",
    "main": "lib/index.js",
    "types": "myLib.d.ts",
}

Процесс поиска выглядит следующим образом:

1. Сначала найдите myLib.d.ts

2. Не найти index.d.ts

3. Я пока не нашел LiB/INDEX.D.JS.

4. Если вы не можете его найти, вы думаете, что объявления типа нет.

резюме

Друзья, которые могут видеть здесь, оцениваются какнастоящий фанатХа-ха, на самом деле ТС не так сложен, как все думают, может быть, он будет более устойчивым или сложным в использовании, когда вы впервые войдете в контакт, но пока вы придерживаетесь его, вы найдете его постепенно.истинный закон ароматаДавайте начнем, не нужно преследовать, насколько фантазии или продвинуты, если использованиени за чтоиспользовать в случаелюбой ДафаЭто не невозможно. Короче говоря, это первое, что нужно использовать. Только путем постоянной практики, основанной на реальном бою, вы можете окончательно овладеть технологией.СущностьЭтот документ Брата Акулы является только теоретическим знанием.Вы должны пойти и больше практиковаться.Кроме того, этот документ основан на текущих ресурсах из нескольких источников в Интернете и на собственном мышлении Брата Акулы.СравнительноРуководство по изучению TS также благодарит много отличных блогеров для своих предыдущих TS статей, таких как abaoge Junjie jimmy_kiwi и так далее

Ссылки на прошлые статьи

Группа передовых рыболовных технологий Brother Shark

Приветствую всех на технических биржахСвязь

爱你.jpg