Написание высококачественного поддерживаемого кода: Awesome TypeScript

внешний интерфейс
Написание высококачественного поддерживаемого кода: Awesome TypeScript

Это 84-я оригинальная статья без воды.Если вы хотите получить больше оригинальных статей, выполните поиск в официальном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Написание высококачественного поддерживаемого кода: Awesome TypeScript

предисловие

Качественный и удобный в сопровождении код должен обладать такими характеристиками, как высокая читабельность, четкая структура, низкая связанность и простота расширения. Однако нативный JavaScript не подходит для разработки и сопровождения крупномасштабных приложений из-за его слабой типизации и отсутствия модульности, поэтому на свет появился TypeScript.

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

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

Typescript VS Javascript

JavaScript

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

TypeScript

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

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

Важные особенности

тип данных

  • Основные типы данных включают в себя: Boolean, Number, String, Array, Enum, Any, Unknown, Tuple, Void, Null, Undefined, Never. Давайте выберем несколько специфичных для TypeScript типов для подробного объяснения:

    • Перечисление перечисления: в процессе кодирования необходимо избегать жесткого кодирования.Если константа может быть перечислена одна за другой, рекомендуется использовать тип перечисления для ее определения, что может упростить поддержку кода.
    // 包括 数字枚举、字符串枚举、异构枚举(数字和字符串的混合)。
    // 数字枚举在不设置默认值的情况下,默认第一个值为0,其他依次自增长
    enum STATUS {
      PENDING,
      PROCESS,
      COMPLETED,
    }
    let status: STATUS = STATUS.PENDING;  // 0
    
    • Любой тип: не рекомендуется. Тип Any является типом верхнего уровня, и все типы можно рассматривать как любой тип.Использование Any эквивалентно отключению механизма проверки типов TypeScript.
    • Неизвестный тип: Неизвестный тип также является типом верхнего уровня, он может принимать любой тип, но отличается от Any тем, что определяет тип данных после первого присваивания, и не позволяет изменить тип данных переменной дважды. Поэтому в сценариях, где вам нужно получить все типы, предпочтительнее использовать Unknown вместо Any.
      • Кортеж: поддерживает хранение элементов разных типов данных в массиве, что позволяет нам быть более гибкими при организации данных.
    let tupleType: [string, boolean];
    tupleType = ["momo", true];
    
    • Тип Void: когда функция не имеет возвращаемого значения, тип возвращаемого значения функции обычно устанавливается равным void.

введите аннотацию

  • TypeScript обеспечивает статическую проверку типов во время компиляции с помощью аннотаций типов, которые могут найти потенциальные ошибки на этапе компиляции и сделать подсказки в процессе кодирования более интеллектуальными. Он прост в использовании, в:Вы можете указать тип переменной после двоеточия.
const str: string = 'abc';

интерфейс

  • Внутри объектно-ориентированного программирования интерфейс является ключом к реализации развязки программы, которая только определяет, какие атрибуты и методы включены, без каких-либо конкретных деталей реализации. Интерфейс основан на классе, дополнительных абстрактных сущностях или поведении, что позволяет программе иметь лучшую масштабируемость.
  • Сценарий приложений: Например, когда мы реализуем функции, связанные с заказами, нам нужно абстрактное порядок, определить интерфейс заказа, включая базовую информацию о заказе и связанные с ними операции, а затем дополнительно реализовывать на основе этого интерфейса. Если связанная функция операции изменений заказа в будущем нужно только переопределить класс для реализации этого интерфейса.
interface Animal {
name: string;
getName(): string;
}
class Monkey implements Padder {
constructor(private name: string) {
  getName() {
    return 'Monkey: ' + name;
	}
}
}

Добрый

  • В дополнение к включению самых основных свойств и методов, геттеров и сеттеров, наследования и других функций, классы TypeScript также добавляют частные поля. К закрытым полям нельзя получить доступ за пределами содержащего класса или даже обнаружить. В классах Javascript нет частных полей.Если вы хотите имитировать частные поля, вы должны использовать замыкания для их имитации. Вот несколько примеров, иллюстрирующих использование следующих классов:
  • свойства и методы
class Person {
// 静态属性
static name: string = "momo";
// 成员属性
gender: string;
// 构造函数
constructor(str: string) {
  this.gender = str;
}
// 静态方法
static getName() {
  return this.name;
}
// 成员方法
getGender() {
  return 'Gender: ' + this.gender;
}
}
let person = new Person("female");
  • геттеры и сеттеры
    • Инкапсуляция данных и проверка достоверности реализованы с помощью методов получения и установки для предотвращения появления аномальных данных.
class Person {
private _name: string;
get name(): string {
  return this._name;
}
set name(newName: string) {
  this._name = newName;
}
}
let person = new Person('momo');
console.log(person.name); // momo
person.name = 'new_momo';
console.log(person.name); // new_momo
  • наследовать
class Animal {
name: string;
constructor(nameStr=:string) {
  this.name = nameStr;
}  
move(distanceInMeters: number = 0) {
  console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Snake extends Animal {
constructor(name: string) {
  super(name);
} 
move(distanceInMeters = 5) {
  super.move(distanceInMeters);
}
}
let snake = new Snake('snake');
snake.move(); // 输出:'snake moved 5m'
  • частное поле
    • Частные поля начинаются с#начинается персонаж. К закрытым полям нельзя получить доступ за пределами содержащего класса или даже обнаружить.
class Person {
#name: string;
constructor(name: string) {
  this.#name = name;
}
greet() {
 	console.log(`Hello, ${this.#name}!`);
}
}
let person = new Person('momo');
person.#name;   // 访问会报错

Дженерики

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

  • общий интерфейс

    interface identityFn<T> {
      (arg: T): T;
    }
    
  • общий класс

    class GenericNumber<T> {
      zeroValue: T;
      add: (x: T, y: T) => T;
    }
    let myGenericNumber = new GenericNumber<number>();
    myGenericNumber.zeroValue = 0;
    myGenericNumber.add = function (x, y) {
      return x + y;
    };
    
  • Общая переменная

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

    • T (тип): представляет тип TypeScript.
    • K (ключ): представляет тип ключа в объекте.
    • V (значение): представляет тип значения в объекте.
    • E (Элемент): указывает тип элемента

перекрестный тип

  • Кросс-тип — это объединение нескольких типов в один тип. пройти через&определение оператора. В следующем примере тип Person и тип Company объединяются для создания нового типа Staff, в котором есть все члены обоих типов.
interface Person {
name: string;
gender: string;
}
interface Company {
companyName: string;
}
type Staff = Person & Company;
const staff: Staff = {
name: 'momo',
gender: 'female',
companyName: 'ZCY'
};

тип объединения

  • Тип объединения — это комбинация нескольких типов с отношением ИЛИ, если выполняется один из них. пройти через|определение оператора. В следующем примере входной параметр функции может иметь строковый или числовой тип.
function fn(param: string | number): void {
  console.log("This is the union type");
}

защита типа

  • Защита типа заключается в безопасном вызове свойств и методов, соответствующих этому типу данных, когда мы определили, что текущие данные относятся к определенному типу данных. Общие виды защиты включаютinтип защиты,typeofтип защиты,instanceofзащита типа и自定义Защита типа. Подробности смотрите в следующих примерах:

    • inзащита типа
    interface Person {
      name: string;
      gender: string;
    }
    interface Employee {
      name: string;
      company: string;
    }
    type UnknownStaff = Person | Employee;
    function getInfo(staff: UnknownStaff) {
      if ("gender" in staff) {
        console.log("Person info");
      }
      if ("company" in staff) {
        console.log("Employee info");
      }
    }
    
    • typeofзащита типа
    function processData(param: string | number): unknown {
    	if (typeof param === 'string') {
      	return param.toUpperCase()
      }
      return param;
    }
    
    • instanceofЗащита типа: иtypeofАналогичный тип использования, он в основном используется для определения того, является ли объект объектом класса или унаследованным.
    function processData(param: Date | RegExp): unknown {
    	if (param instanceof Date) {
      	return param.getTime();
      }
      return param;
    }
    
    • 自定义Защита типа: через предикат типаparameterName is Typeдля реализации пользовательской защиты типа. В следующем примере реализована защита типа параметров запроса интерфейса.
    interface ReqParams {
    	url: string;
     	onSuccess?: () => void;
     	onError?: () => void;
    }
    // 检测 request 对象包含参数符合要求的情况下,才返回 url
    function validReqParams(request: unknown): request is ReqParams {
    	return request && request.url
    }
    

советы по развитию

  • Необходимо постоянно судить о том, есть ли в объекте определенный атрибут глубокого уровня, вы можете использовать?.
if(result && result.data && result.data.list) // JS
if(result?.data?.list) // TS
  • Чтобы совместно судить, является ли это нулевым значением, вы можете использовать??
let temp = (val !== null && val !== void 0 ? val : '1'); // JS
let temp = val ?? '1'; // TS
  • Не полагайтесь исключительно на проверку типов и при необходимости пишите защитный код.

    • Поскольку ошибка типа не повлияет на генерацию и выполнение кода, в принципе существует возможность вызова fn('str'), поэтому для защитного кода необходимо значение по умолчанию.
function fn(value:boolean){
	switch(value){
  	case true: 
    	console.log('true');
      break;
    case false: 
      console.log('false');
      break;
    default: 
      console.log('dead code');
  }
}
  • Для функций строго контролируйте тип возвращаемого значения.
// 推荐写法
function getLocalStorage<T>(key: string): T | null {
  const str = window.localStorage.getItem(key);
  return str ? JSON.parse(str) : null;
}
const data = getLocalStorage<DataType>("USER_KEY");
  • Реализация фабричного шаблона с помощью new()

    • Синтаксис TypeScript для реализации фабричного шаблона очень прост: вам нужно только сначала определить функцию, объявить параметр типа конструктора, а затем вернуть объект, созданный классом c, в теле функции. В следующем примере фабричная функция создает объект типа T.
function create<T>(c: { new(): T }): T {
	return new c();
}
class Test {
  constructor() {
  }
}
create(Test);
  • Предпочитать неизвестный тип любому

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

function fn(arr:readonly number[] ){
  let sum=0, num = 0;
  while((num = arr.pop()) !== undefined){
    sum += num;
  }
  return sum;
}
  • Используйте Enum для поддержки постоянной таблицы для более безопасной проверки типов.
// 使用 const enum 维护常量
const enum PROJ_STATUS {
  PENDING = 'PENDING',
  PROCESS = 'PROCESS',
  COMPLETED = 'COMPLETED'
}
function handleProject (status: PROJ_STATUS): void {
}
handleProject(PROJ_STATUS.COMPLETED)
  • Рекомендуется включить следующие параметры проверки компиляции, чтобы облегчить обнаружение потенциальных ошибок в среде компиляции.
{
  "compilerOptions": {
    /* 严格的类型检查选项 */
    "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 语句贯穿)
  }
}

Связанные плагины VSCode

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

  • TSLint: автоматическое обнаружение и исправление несовместимого кода TypeScript.
  • TypeScript Hero: Сортировка и организация порядка импорта модулей, удаление неиспользуемых модулей. Ярлыки в MacOSCtrl+Opt+o, сочетания клавиш в Win/LinuxCtrl+Alt+o.
  • json2ts: преобразование JSON из буфера обмена в интерфейс TypeScript. Ярлыки в MacOSCtrl+Opt+V, сочетания клавиш в Win/LinuxCtrl+Alt+V.
  • Переместить TS: при перемещении файлов TypeScript или папок, содержащих файлы TypeScript, пути импорта связанных зависимых модулей автоматически обновляются.
  • Path Intellisense: автоподсказка для путей и имен файлов.
  • Средство импорта TypeScript: при импорте модуля он автоматически ищет все экспортированные модули в текущей рабочей области и автоматически выполняет запрос.
  • Prettier — средство форматирования кода: форматирование кода.

Рекомендуемое чтение

Саморазвитие фронтенд-инженеров: как React Fiber делает процесс обновления контролируемым

Утилизация мусора двигателя V8 и выделение памяти

Карьера

ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 40 фронтенд-партнеров, средний возраст которых составляет 27 лет, и почти 30% из них — инженеры полного стека, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.

Если вы хотите измениться, вас забрасывают вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года стажа работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com