Резюме основных точек знаний TS и анализа проекта

JavaScript TypeScript
Резюме основных точек знаний TS и анализа проекта

предисловие

В последнее время работа была очень загружена, и цикл проверки тоже удлинился, но я все равно буду настаивать на еженедельной проверке. Сегодня я пересмотрюtypescriptПрименение во front-end проектах, почему стоит учитьсяtypescript, я думаю, что все самоочевидно, текущий мейнстримный фреймворкvueа такжеreactИ большая часть внутренней конструкции соответствующей экологии принимаетtypescript, причина в том, что его статическая проверка типов значительно улучшает читабельность и удобство сопровождения кода, а также очень удобно локализовать проблемы. Предыдущий ниже оtypescriptОфициальное определение для вашего удобства:

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

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

резюме

Изучение любого языка требует системы обучения и мышления, и интерфейс не является исключением, автор объяснит его в соответствии со структурой, показанной на следующем рисунке:

текст

Наша текущая разработка проекта является наиболее используемойwebpack, для ts мы также можем легко пройтиts-loaderДля его компиляции и настройки, с целью снижения сложности изучения ts, автор рекомендует использоватьvue-cli3илиumiСоздайте проект ts напрямую, чтобы вы могли быстрее приступить к разработке ts.

основные очки знаний

1. Базовый тип

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

// 布尔类型
let isCookie:boolean = true

// 数值类型
let myMoney:number = 12

// 字符串类型
let name:string = '徐小夕'

// 数组类型, 有两种表示方式,第一种可以在元素类型后面接上[],表示由此类型元素组成的一个数组
let arr:number[] = [1,2,2]

// 数组类型, 使用数组泛型
let arr:Array<number> = [1,2,2]

// 元组类型, 允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
let xi: [string, number];
// 初始化xi
xi = ['xu', 10]; // 正确
xi = [11, 'xu']; // 错误

// 枚举类型, 可以为一组数值赋予友好的名字
enum ActionType { doing, done, fail }
let action:ActionType = ActionType.done    // 1

// any, 表示任意类型, 可以绕过类型检查器对这些值进行检查
let color:any = 1
color = 'red'

// void类型, 当一个函数没有返回值时,通常会设置其返回值类型是 void
function getName(): void {
    console.log("This is my name");
}

// object类型, 表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型
let a:object;
a = {props: 1}

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

let arrLen: number = (someValue as Array<string>).length;
// 解决window下设置属性的ts报错, 但不可滥用
(window as any).name = 'xuxi'

2. Интерфейс

Одним из основных принципов TypeScript является проверка типа структуры значения.В TypeScript роль интерфейсов состоит в том, чтобы называть эти типы и определять контракты для вашего кода или стороннего кода. Далее мы рассмотрим, как определить и использовать интерфейс (Interface):

interface Product {
  name: string;
  size: number;
  weight: number;
}

let product1:Product = {
	name: 'machine1',
    size: 20,
    weight: 10.5
}

Средство проверки типов не проверяет порядок свойств, если соответствующее свойство существует и тип правильный. Во-вторых, мы также можем определитьнеобязательный атрибута такжесвойство только для чтения. необязательный атрибутУказывает, что некоторые свойства в интерфейсе не требуются, поэтому их можно определить или нет.Читаемое свойствоНекоторые свойства в интерфейсе можно только читать, но не назначать. Конкретные случаи:

interface Product {
  name: string;
  size?: number;
  readonly weight: number;
}

В реальных сценариях мы часто сталкиваемся с неопределенными именами свойств и типами значений свойств. Такая ситуация часто возникает при доступе сторонних SDK или внутренних ответах. В настоящее время мы можем использоватьподпись индексаДля установки дополнительных свойств и типов дело обстоит следующим образом:

interface App {
  name: string;
  color?: number;
  [propName: string]: any;
}

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

interface MyFunc {
  (value:string, type: number): boolean;
}
// 使用
let myLoveFront: MyFunc;
myLoveFront = function(value:string, type: number) {
 	return type > 1
}

мы вvueа такжеreactВ разработке также часто используетсяclassЭтот тип класса используется для написания повторно используемых компонентов и библиотек. Поскольку ts может описывать типы функций, можно ли его также использовать для описания типов классов? Ответ - да. Но определение интерфейса класса немного сложно, как мы все знаем.Классы имеют два типа: тип статической части и тип экземпляра.Когда класс реализует интерфейс, проверяется тип только его экземплярной части. Конструктор находится в статической части класса, поэтому не проверяется., Это предложение довольно критично. Мы также должны сосредоточиться на этой функции при определении интерфейса класса. Дело в следующем:

interface TickConstructor {
    new (hour: number, minute: number): TickInterface;
}
interface TickInterface {
    tick();
}

function createClock(ctor: ClockConstructor, hour: number, minute: number): TickInterface {
    return new ctor(hour, minute);
}

class DigitalClock implements TickInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("xu xu");
    }
}
class MyTick implements TickInterface {
    constructor(h: number, m: number) { }
    tick() {
        console.log("tick tock");
    }
}

let digital = createClock(DigitalTick, 12, 17);
let analog = createClock(MyTick, 7, 32);

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

3. Класс

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

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

Конкретные случаи следующие:

class Person {
    protected name: string;
    constructor(name: string) { this.name = name; }
}

class Employee extends Person {
    private department: string;

    constructor(name: string, department: string) {
        super(name)
        this.department = department;
    }

    public getElevatorPitch() {
        return `Hello, my name is ${this.name} and I work in ${this.department}.`;
    }
}

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

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

Краткое введение в случай абстрактных классов выглядит следующим образом:

abstract class MyAbstract {
    constructor(public name: string) {}
    say(): void {
        console.log('say name: ' + this.name);
    }
    abstract sayBye(): void; // 必须在派生类中实现
}

class AccountingMyAbstract extends MyAbstract {
    constructor() {
        super('小徐'); // 在派生类的构造函数中必须调用 super()
    }
    sayBye(): void {
        console.log('趣谈小夕.');
    }
    getOther(): void {
        console.log('loading...');
    }
}

let department: MyAbstract; // 允许创建一个对抽象类型的引用
department = new MyAbstract(); // 错误: 不能创建一个抽象类的实例
department = new AccountingMyAbstract(); // 允许对一个抽象子类进行实例化和赋值
department.say();
department.sayBye();
department.getOther(); // 错误: 方法在声明的抽象类中不存在

4. Функция

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

function createName(firstName: string, lastName?: string) {
    if (lastName)
        return firstName + " " + lastName;
    else
        return firstName;
}

Обратите внимание, что наши необязательные параметры должны следовать за обязательными параметрами.

5. Дженерики

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

function iSay<T>(arg: T): T {
    return arg;
}
// 调用泛型函数
let come = iSay<number>(123); 

Мы даем ISAY добавить переменную типа T. T помогла нам захватить входящий тип пользователя (например, string), чтобы мы могли использовать этот тип. Затем мы снова используем T в качестве типа возврата. Теперь мы можем знать типы параметров, а тип возврата одинаковы. Это позволяет нам отслеживать использование функции в типе информации.

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

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

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

interface SayLove {
	<T>(arg: T): T
}

// 把泛型参数当作整个接口的一个参数
interface SayLoveArg<T> {
	(arg: T): T
}

// 泛型函数
function iSay<T>(arg: T): T {
    return arg;

let mySay1:SayLove = iSay
let mySay2:SayLoveArg<number> = iSay

Точно так же мы можем также определить универсальные классы. Нам нужно только использовать (), чтобы заключить универсальный тип и следовать за именем класса. Конкретные случаи следующие:

class MyNumber<T> {
    year: T;
    compute: (x: T, y: T) => T;
}

let myGenericNumber = new MyNumber<number>();

Мы также можем определитьобщие ограничениядля более точного управления типом класса Дело в следующем:

interface NumberControl {
	length: number
}

class MyObject<T extends NumberControl>(arg: T):T {
	console.log(arg.length)
    return arg
}

6. Расширенные типы

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

  • перекрестный тип
  • тип союза
  • Полиморфный этот тип
  • Операторы запроса типа индекса
  • оператор доступа к индексу

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

function extend<T, U>(first: T, second: U): T & U {
    let result = <T & U>{};
    for (let id in first) {
        (<any>result)[id] = (<any>first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (<any>result)[id] = (<any>second)[id];
        }
    }
    return result;
}

мы передаем символы&для представления объединения, и в этом случае возвращаемое значение в приведенном выше коде будет иметь типы T и U.

тип союзаУказывает, что значение может быть одного из нескольких типов. Мы разделяем каждый тип вертикальной чертой (|), поэтому число | строка | логическое значение означает, что значение может быть числом, строкой или логическим значением. Конкретные примеры следующие:

let name: string | number = 'xuxiaoxi'

function sayName(name: string):(string|number) { 
  return name 
}

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

Другим общим требованием является то, что после того, как мы реализуем наш собственный класс, нам нужно поддерживать цепочку вызовов методов класса.typescriptнам нужно понятьПолиморфный этот тип, Он представляет собой подтип содержащего класса или интерфейса. Это называется F-ограниченным полиморфизмом. Чтобы поддерживать цепочку в машинописном тексте, мы можем написать:

class MyCalculator {
    public constructor(number = 0) { }
    public add(n: number): this {
        this.value += n;
        return this;
    }
    public multiply(n: number): this {
        this.value *= n;
        return this;
    }
    // ... 其他操作 ...
}

let v = new MyCalculator(2).multiply(5).add(1);

Следующее, что нам нужно знать, этоОператоры запроса типа индекса, Общее использованиеkeyofВыражать. Для любого типа T результатом keyof T является объединение известных имен общедоступных свойств на T. Например, мы определяем интерфейс Animal:

interface Animal {
    cat: string;
    dog: string;
}

let AnimalProps: keyof Animal; // 'cat' | 'dog'

keyof Animal полностью взаимозаменяем с 'cat' | 'dog'. Разница в том, что если мы добавим к Animal другие свойства, такие как pig:string, то keyof Animal автоматически станет 'кот' | 'собака' | 'свинья'.

7. Пространства имен

Пространства именОсновная цель — организовать ваш код так, чтобы вы могли записывать их типы, не беспокоясь о конфликтах имен с другими объектами. Поскольку использование пространства имен очень простое, здесь мы возьмем в качестве примера популярную в Интернете D3, код выглядит следующим образом:

declare namespace D3 {
    export interface Selectors {
        select: {
            (selector: string): Selection;
            (element: EventTarget): Selection;
        };
    }

    export interface Event {
        x: number;
        y: number;
    }

    export interface Base extends Selectors {
        event: Event;
    }
}

declare var d3: D3.Base;

8. Используйте сторонние библиотекиПосле ознакомления с приведенными выше базовыми знаниями давайте посмотрим, как использовать стороннюю библиотеку классов, которая поддерживает машинописный текст.Например, наш часто используемый lodash, тогда правильные шаги использования следующие:

// 安装lodash和对应的类型文件
npm install --save lodash @types/lodash

// 在代码中使用
import * as _ from "lodash";
_.padStart("Hello xuxiaoxi!", 12, " ");

9. Декларационный документФайл объявления также является очень важной точкой знаний.При использовании необъявленных глобальных функций или глобальных переменных машинописный текст часто сообщает об ошибках, поэтому мы можем добавить файл xxx.d.ts в соответствующее место и объявить в нем нужные нам переменные. . , ts автоматически извлечет файл и проанализирует его. Ниже приведены несколько случаев для справки и изучения:

// global.d.ts

// 声明全局变量
declare var name: string;

// 全局函数
declare function say(name: string): void;

// 带属性的对象
declare namespace myObj {
    function say(s: string): string;
    let money: number;
}

// 可重用的接口
interface Animal {
	kind: string;
    age: number;
    weight?: number;
}
declare function findAnmiate(animal:Animal):void

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

Битва проекта React + Typescript

1. Используйте umi для создания проекта react+typescript

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

2. Определите файл глобального объявления

Мы создаем файл global.d.ts в каталоге src проекта в качестве файла глобального объявления для обработки глобальных объявлений и совместимости со сторонними библиотеками.

3. Используйте ts для реализации библиотеки классов инструментовМы создаем каталог utils в каталоге src для хранения наших классов инструментов или общих библиотек.Например, мы создаем новый tool.ts под utils в качестве нашей общей функции инструмента.Здесь мы пишем самый простой пример:

/**
* 生成uuid
*/
const uuid = ():string => {
    let s:Array<any> = [];
    let hexDigits:string = "0123456789abcdef";
    for (let i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4"; 
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); 
    s[8] = s[13] = s[18] = s[23] = "-";
    let uuid = s.join("");
    return uuid;
};

// 可以来自于外部的type.ts文件
interface Params {
  [propName: string]: string | number
}

/**
 * reverseJson 反转对象键值对
 * @param {object} obj 待反转的对象
 * @param {object} target 反转的目标对象
 */
const reverseJson = (obj:Params = {}, target:Params = {}):Params => {
  Object.keys(obj).forEach((key:string) => { target[obj[key]] = key })
  return target
}

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

4. Использование машинописного текста в компонентах React

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

наконец

Если вы хотите узнать большеигра Н5, webpack,node,gulp,css3,javascript,nodeJS,визуализация данных холстаВ ожидании передовых знаний и реальных сражений, добро пожаловать в нашу техническую группу в общедоступном аккаунте «Интересный передний конец», чтобы вместе учиться и обсуждать, а также вместе исследовать границы переднего плана.

больше рекомендаций