Тренажерный опыт

JavaScript TypeScript

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

1. Как решать проблемы, связанные с типами сторонних библиотек

Определения типов сторонних библиотек, предоставляемые Typescipt, не только ограничивают наши входные вызовы, но и предоставляют нам документацию.Теперь в NPM существует так много типов определений сторонних типов, что трудно гарантировать, что определения типов Также трудно гарантировать, что все используемые сторонние библиотеки имеют определения типов. Итак, в этом неизвестном процессе, как правильно использовать сторонние библиотеки в TypeScript? Вот четыре распространенных сценария, которые не работают, и соответствующие решения:

  • Сама библиотека не имеет собственного определения типа
  • В самой библиотеке нет определений типов и связанных с ними @type.
  • неверная библиотека объявления типов
  • Ошибка объявления типа
  1. Сама библиотека не имеет собственного определения типа Не удалось найти соответствующий тип библиотеки. Например

    При преобразовании реакции на поддержку машинописного текста в первый раз многие люди, должно быть, столкнулись с ошибками module.hot.В настоящее время необходимо установить только соответствующую библиотеку типов.Установите @types/webpack-env

  2. В самой библиотеке нет определений типов и связанных с ними @type. Тогда вы можете объявить только один самостоятельно.Просто дайте каштан.

declare module “lodash”
  1. неверная библиотека объявления типов
  • Нажмите, чтобы разрешить проблемы с определениями официального типа, поднять вопросы, PR
  • После импорта исходный тип может быть расширен с возможностью расширения или слияния.
  • Терпеть потерю типа или ненадежность
  • // @ts-ignore игнорирует
  1. Ошибка объявления типа
  • Добавить «skipLibCheck»: true в компилятореOptions, кривая заставка

2. Используйте сокращение шрифта для устранения ошибок

Существует несколько распространенных решений ниже:

  • утверждение типа
  • защита типа typeof in instanceof защита типа литерала
  • двойное утверждение

1. Утверждение типа Утверждения типа могут явно указать TypeScript подробный тип значения, В некоторых случаях мы очень уверены в его типе, даже если он не соответствует типу, выведенному машинописным текстом, тогда мы можем использовать утверждение типа. Синтаксис следующий:

<类型>值
值 as 类型 // 推荐使用这种语法. 因为<>容易跟泛型, react 中的语法起冲突

Например, в следующем коде значение заполнения может быть либо строкой, либо числом.Хотя в коде написано Array(), мы ясно знаем, что заполнение будет преобразовано в числовой тип с помощью parseint, но определение типа все равно сообщит об ошибке. ошибка.

function padLeft(value: string, padding: string | number) {
  // 报错: Operator '+' cannot be applied to 
  // types 'string | number' and 'number'
  return Array(padding + 1).join(" ") + value;
}

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

function padLeft(value: string, padding: string | number) {
  // 正常
  return Array(padding as number + 1).join(" ") + value;
}

Но если есть следующая ситуация, нужно ли нам писать много as?

function padLeft(value: string, padding: string | number) {
    console.log((padding as number) + 3);
    console.log((padding as number) + 2);
    console.log((padding as number) + 5);
    return Array((padding as number) + 1).join(' ') + value;
}

2. Тип гвардии Существует несколько типов охранников типа, которые вкратце можно описать следующим образом.

  • typeof: используется для определения четырех типов «число», «строка», «логическое значение» или «символ».
  • instanceof : используется для определения принадлежности экземпляра к классу
  • in: используется для определения того, принадлежит ли свойство/метод объекту
  • литеральная защита типа

В приведенном выше примере он имеет тип string | number, поэтому typeof используется для защиты типа.Пример выглядит следующим образом:

function padLeft(value: string, padding: string | number) {
    if (typeof padding === 'number') {
        console.log(padding + 3); //正常
        console.log(padding + 2); //正常
        console.log(padding + 5); //正常 
        return Array(padding + 1).join(' ') + value; //正常
    }
    if (typeof padding === 'string') {
        return padding + value;
    }
}

По сравнению с утверждением типа as это экономит много кода.В дополнение к typeof у нас есть несколько способов, ниже приведены примеры.

  • InstanceOf --- используется для определения принадлежности экземпляра к определенному классу.
class Man {
    handsome = 'handsome';
}
class Woman {
    beautiful = 'beautiful';
}

function Human(arg: Man | Woman) {
    if (arg instanceof Man) {
        console.log(arg.handsome);
        console.log(arg.beautiful); // error
    } else {
        // 这一块中一定是 Woman
        console.log(arg.beautiful);
    }
}
  • in --- Используется для определения того, принадлежит ли свойство/метод объекту
interface B {
    b: string;
}
interface A {
    a: string;
}
function foo(x: A | B) {
    if ('a' in x) {
        return x.a;
    }
    return x.b;
}
  • литеральная защита типа

В некоторых сценариях использование in, instanceof, typeof слишком затруднительно, в этом случае литеральный тип можно сконструировать самостоятельно.

type Man = {
    handsome: 'handsome';
    type: 'man';
};
type Woman = {
    beautiful: 'beautiful';
    type: 'woman';
};

function Human(arg: Man | Woman) {
    if (arg.type === 'man') {
        console.log(arg.handsome);
        console.log(arg.beautiful); // error
    } else {
        // 这一块中一定是 Woman
        console.log(arg.beautiful);
    }
}

3. Двойное утверждение Иногда использование as также приводит к ошибке, поскольку утверждение as не является безусловным и может быть успешно утверждено как T, только если тип S является подмножеством типа T или тип T является подмножеством типа S. Итак, перед лицом этой ситуации, если вы просто хотите решить проблему насильственно, вы можете использовать двойное утверждение.

function handler(event: Event) {
  const element = event as HTMLElement; 
  // Error: 'Event' 和 'HTMLElement' 中的任何一个都不能赋值给另外一个
}

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

function handler(event: Event) {
  const element = (event as any) as HTMLElement; // 正常
}

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

  1. Необязательная цепочка
let x=foo?.bar.baz();

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

var _a;
let x = (_a = foo) === null || _a === void 0 ? void 0 : _a.bar.baz();

Используя эту функцию, мы можем сохранить много неприятного кода, такого как && a.b && a.b.c.

  1. Нулевое слияние
let x =foo ?? '22';

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

let x = (foo !== null && foo !== void 0 ? foo : '22');

4. Используйте расширенные типы для гибкой обработки данных

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

  • индекс типа

Чтобы реализовать вышеуказанную служебную функцию, нам нужно понять следующий синтаксис: keyof : получить значение ключа для типа extends : ограничения в дженериках T[K] : получить тип элемента соответствующего K объекта T

type Partial<T> = {
    [P in keyof T]?: T[P]
}

При использовании props иногда все свойства необязательны.Если писать ? по одному, много повторяющихся действий.В этом случае можно использовать Partial напрямую

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

type Record<K extends string, T> = {
    [P in K]: T;
}

Давайте посмотрим на этот объект ниже, как бы вы объявили его с помощью ts?

const AnimalMap = {
    cat: { name: '猫', title: 'cat' },
    dog: { name: '狗', title: 'dog' },
    frog: { name: '蛙', title: 'wa' },
};

Вы можете использовать запись в это время.

type AnimalType = 'cat' | 'dog' | 'frog';
interface AnimalDescription { name: string, title: string }
const AnimalMap: Record<AnimalType, AnimalDescription> = {
    cat: { name: '猫', title: 'cat' },
    dog: { name: '狗', title: 'dog' },
    frog: { name: '蛙', title: 'wa' },
};
  • никогда, создает условные типы

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

грамматика:

never: 从未出现的值的类型

// 如果 T 是 U 的子类型的话,那么就会返回 X,否则返回 Y
构造条件类型 : T extends U ? X : Y 
type Exclude<T, U> = T extends U ? never : T;

// 相当于: type A = 'a'
type A = Exclude<'x' | 'a', 'x' | 'y' | 'z'>
  • Более лаконичные модификаторы: - и + Вы можете напрямую удалить ?, чтобы сделать все свойства объекта обязательными.
type Required<T> = { [P in keyof T]-?: T[P] };

// Remove readonly
type MutableRequired<T> = { -readonly [P in keyof T]: T[P] };  
  • infer: переменная типа для вывода в условном операторе extends.
// 需要获取到 Promise 类型里蕴含的值
type PromiseVal<P> = P extends Promise<infer INNER> ? INNER : P;
type PStr = Promise<string>;

// Test === string
type Test = PromiseVal<PStr>;

5. Определите тип и интерфейс

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

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

An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.

An interface can have multiple merged declarations, but a type alias for an object type literal cannot.

Посмотрите разницу между ними на картинке:

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

6. Постоянное перечисление

Для конфиденциальных данных можно использовать постоянный метод перечисления.

const enum learn { 
    math,
    language,
    sports
}

После компиляции он пустой:

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

Прошлые статьи:

Добро пожаловать, чтобы обратить внимание на «Front-end Plus», серьезно изучить интерфейс и стать профессиональным техником...