введение
Как мощный инструмент статической проверки типов, TypeScript теперь можно найти во многих средних и крупных приложениях, а также в популярных библиотеках JS. Как язык со слабой типизацией, JS изменит тип переменных, если мы не будем осторожны в процессе написания кода, что приведет к некоторым неожиданным ошибкам во время выполнения. Однако TypeScript может помочь нам решить эту проблему в процессе компиляции: он не только вводит строгую проверку типов в JS, но и скомпилированный код JS может работать в любой среде браузера, среде Node и любой версии, поддерживающей ECMAScript 3 (или выше). . ) в движке JS. В последнее время компания только готовится использовать TypeScript для рефакторинга существующей системы.В прошлом было не так много возможностей использовать TypeScript, особенно для какого-то полезного расширенного использования.Если есть ошибки, пожалуйста, укажите на них.
1. Наследование классов
В ES5 мы обычно инкапсулируем общие части некоторых компонентов с помощью наследования на основе функций или прототипов, чтобы облегчить повторное использование, однако в TypeScript мы можем использовать наследование классов объектно-ориентированным способом, как в Java, для создания повторно используемых компонентов. мы можем пройтиclass
ключевое слово, чтобы создать класс и использовать его на основеnew
оператор для создания экземпляра объекта. Чтобы абстрагировать общие части нескольких классов, мы можем создать родительский класс и позволить дочернему классу передатьextends
Ключевые слова для наследования родительского класса, тем самым сокращая написание некоторого избыточного кода и повышая возможность повторного использования и ремонтопригодность кода. Пример выглядит следующим образом:
class Parent {
readonly x: number;
constructor() {
this.x = 1;
}
print() {
console.log(this.x);
}
}
class Child extends Parent {
readonly y: number;
constructor() {
// 注意此处必须优先调用super()方法
super();
this.y = 2;
}
print() {
// 通过super调用父类原型上的方法,但是方法中的this指向的是子类的实例
super.print();
console.log(this.y);
}
}
const child = new Child();
console.log(child.print()) // -> 1 2
В приведенном выше примереChild
подкласс к родительскому классуprint
метод, который будет переопределен и использован внутриsuper.print()
для вызова общедоступной логики родительского класса для повторного использования логики.class
Ключевые слова используются в качестве синтаксического сахара для конструкторов, после компиляции TypeScript они в конечном итоге преобразуются в код ES5, распознаваемый браузерами с хорошей совместимостью.class
Это очень распространено в парадигме объектно-ориентированного программирования, поэтому, чтобы понять механизм реализации, стоящий за этим, мы могли бы также потратить больше времени, чтобы увидеть, как выглядит код после компиляции и преобразования (конечно, студенты, которые уже знакомы с с этой частью можно прямо перепрыгнуть).
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Parent = /** @class */ (function () {
function Parent() {
this.x = 1;
}
Parent.prototype.print = function () {
console.log(this.x);
};
return Parent;
}());
var Child = /** @class */ (function (_super) {
__extends(Child, _super);
function Child() {
var _this =
// 注意此处必须优先调用super()方法
_super.call(this) || this;
_this.y = 2;
return _this;
}
Child.prototype.print = function () {
// 通过super调用父类原型上的方法,但是方法中的this指向的是子类的实例
_super.prototype.print.call(this);
console.log(this.y);
};
return Child;
}(Parent));
var child = new Child();
console.log(child.print()); // -> 1 2
Выше приведен полный код после конвертации.Для удобства сравнения здесь сохранена исходная информация комментариев.После внимательного изучения этого кода мы найдем следующие моменты:
-
Подкласс
Child
в конструктореsuper()
метод преобразуется вvar _this = _super.call(this) || this
,здесь_super
относится к родительскому классуParent
, поэтому смысл этого кода в том, чтобы вызвать конструктор родительского класса иthis
Привязать к экземпляру подкласса, чтобы экземпляр подкласса мог иметьx
Атрибуты. Итак, чтобы реализовать наследование свойств, мы должны вызвать конструктор подклассаsuper()
метод, если он не будет вызван, компиляция завершится ошибкой. -
Подкласс
Child
изprint
методsuper.print()
метод преобразуется в_super.prototype.print.call(this)
, смысл этого кода в вызове прототипа родительского классаprint
метод и поместитеthis
Укажите на экземпляр подкласса, потому что мы унаследовали от родительского класса на предыдущем шаге.x
свойство, поэтому здесь мы будем напрямую печатать экземпляр подклассаx
Стоимость имущества. -
extends
Ключевое слово в конечном итоге преобразуется в__extends(Child, _super)
метод, где_super
относится к родительскому классуParent
, для удобства просмотра здесь будет_extends
Методы представлены отдельно для исследования.
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
// 第一部分
extendStatics(d, b);
// 第二部分
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
В приведенном выше коде его можно в основном разделить на две части, чтобы понять, первая частьextendStatics(d, b)
метод, вторая часть — это две строки кода после метода.
第一部分
:
существуетextendStatics
Хотя объем кода внутри метода относительно велик, нетрудно обнаружить, что он в основном должен быть совместим с версией среды выполнения ES5. Добавлено в ES6Object.setPrototypeOf
Метод используется для ручной установки прототипа объекта, но в среде ES5 мы обычно передаем нестандартный__proto__
свойства для установки,Object.setPrototypeOf
Принцип метода заключается собственно в установке прототипа объекта через это свойство, которое реализовано следующим образом:
Object.setPrototypeOf = function(obj, proto) {
obj.__proto__ = proto;
return obj;
}
существуетextendStatics(d, b)
метод,d
Относится к подклассамChild
,b
относится к родительскому классуParent
, поэтому эффект этого метода можно интерпретировать как:
// 将子类Child的__proto__属性指向父类Parent
Child.__proto__ = Parent;
Эту строку кода можно понимать как наследование конструкторов или наследование статических свойств и статических методов, то есть свойства и методы не монтируются в конструкторыprototype
На прототипе она напрямую монтируется в сам конструктор, т.к. сама функция тоже может использоваться как объект в JS, и ей можно присваивать любые другие свойства, примеры такие:
function Foo() {
this.x = 1;
this.y = 2;
}
Foo.bar = function() {
console.log(3);
}
Foo.baz = 4;
console.log(Foo.bar()) // -> 3
console.log(Foo.baz) // -> 4
Итак, когда мы создаем подклассChild
Китай и ИзраильChild.someProperty
При доступе к свойству оно будет передано, если оно не существует в подклассеChild.__proto__
Ищите свойство с тем же именем родительского класса, чтобы таким образом реализовать поиск пути статических свойств и статических методов.
第二部分
:
Включите во вторую часть только следующие две строки кода:
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
вd
Относится к подклассамChild
,b
относится к родительскому классуParent
, здесь студенты, знакомые с несколькими способами реализации наследования в JS, сразу видят, что здесь используется метод паразитного комбинированного наследования, путем заимствования промежуточной функции__()
чтобы избежать при изменении подклассаprototype
метод родительского классаprototype
вызванное воздействие. Мы знаем, что после создания экземпляра объекта через конструктор в JS объект будет иметь__proto__
свойство и указать на его конструкторprototype
свойства, примеры следующие:
function Foo() {
this.x = 1;
this.y = 2;
}
const foo = new Foo();
foo.__proto__ === Foo.prototype; // -> true
В этом примере, если вы передаете подклассChild
После создания экземпляра объекта генерируются следующие ассоциации:
const child = new Child();
child.__proto__ === (Child.prototype = new __());
child.__proto__.__proto__ === __.prototype === Parent.prototype;
// 上述代码等价于下面这种方式
Child.prototype.__proto__ === Parent.prototype;
Итак, когда мы создаем подклассChild
экземплярchild
через объектchild.someMethod()
При вызове метода, если метод не существует в экземпляре, он будет следовать__proto__
Продолжайте искать и в конечном итоге пройдете через родительский классParent
изprototype
Прототипировать, то есть таким образом добиться наследования методов.
На основании анализа двух вышеприведенных частей можно сделать следующие два вывода:
// 表示构造函数的继承,或者叫做静态属性和静态方法的继承,总是指向父类
1. Child.__proto__ === Parent;
// 表示方法的继承,总是指向父类的prototype属性
2. Child.prototype.__proto__ === Parent.prototype;
2. Модификаторы доступа
TypeScript предоставляет нам модификаторы доступа (Access Modifiers) для ограниченияclass
Внешний доступ к внутренним свойствам, модификаторы доступа в основном включают следующие три:
-
public
: общедоступный модификатор, его измененные свойства и методы являются общедоступными и могут быть доступны в любом месте.По умолчанию все свойства и методы являются общедоступными.public
из. -
private
: частный модификатор, чьи измененные свойства и методы находятся вclass
Не видно снаружи. -
protected
: защищенный модификатор иprivate
Аналогичные, но модифицированные свойства и методыДоступ разрешен внутри подклассов.
Давайте сравним несколько модификаторов с некоторыми примерами:
class Human {
public name: string;
public age: number;
public constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const man = new Human('tom', 20);
console.log(man.name, man.age); // -> tom 20
man.age = 21;
console.log(man.age); // -> 21
В приведенном выше примере, поскольку мы установили модификатор доступа вpublic
, так что мы передаем примерman
посещатьname
иage
атрибуты разрешены, аage
Также допускается переуступка имущества. Но в некоторых случаях мы хотим, чтобы некоторые свойства были невидимы для внешнего мира и не допускались к изменению, тогда мы можем использоватьprivate
Модификатор:
class Human {
public name: string;
private age: number; // 此处修改为使用private修饰符
public constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const man = new Human('tom', 20);
console.log(man.name); // -> tom
console.log(man.age);
// -> Property 'age' is private and only accessible within class 'Human'.
мы будемage
Модификатор свойства меняется наprivate
после внешнего проходаman.age
Получите доступ к нему, и TypeScript увидит его как частное свойство во время компиляции и в конечном итоге сообщит об ошибке.
Примечание. Доступ к закрытым свойствам не ограничен в скомпилированном коде TypeScript.
Скомпилированный код выглядит следующим образом:
var Human = /** @class */ (function () {
function Human(name, age) {
this.name = name;
this.age = age;
}
return Human;
}());
var man = new Human('tom', 20);
console.log(man.name); // -> tom
console.log(man.age); // -> 20
использоватьprivate
Свойство или метод, измененный модификаторомДоступ также запрещен в подклассах, пример следующий:
class Human {
public name: string;
private age: number;
public constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class Woman extends Human {
private gender: number = 0;
public constructor(name: string, age: number) {
super(name, age);
console.log(this.age);
}
}
const woman = new Woman('Alice', 18);
// -> Property 'age' is private and only accessible within class 'Human'.
В приведенном выше примере, поскольку родительский классHuman
серединаage
свойство установлено наprivate
, поэтому в подклассеWoman
нельзя получить доступ вage
свойства, чтобы разрешить доступ в подклассахage
свойства, мы можем использоватьprotected
модификатор, чтобы изменить его:
class Human {
public name: string;
protected age: number; // 此处修改为使用protected修饰符
public constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class Woman extends Human {
private gender: number = 0;
public constructor(name: string, age: number) {
super(name, age);
console.log(this.age);
}
}
const woman = new Woman('Alice', 18); // -> 18
когда мы будемprivate
Когда модификатор используется в конструкторе, это означает, что классНе допускается наследование или создание экземпляра, пример следующий:
class Human {
public name: string;
public age: number;
// 此处修改为使用private修饰符
private constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class Woman extends Human {
private gender: number = 0;
public constructor(name: string, age: number) {
super(name, age);
}
}
const man = new Human('Alice', 18);
// -> Cannot extend a class 'Human'. Class constructor is marked as private.
// -> Constructor of class 'Human' is private and only accessible within the class declaration.
когда мы будемprotected
Когда модификатор используется в конструкторе, это означает, что классразрешено только наследование, пример следующий:
class Human {
public name: string;
public age: number;
// 此处修改为使用protected修饰符
protected constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class Woman extends Human {
private gender: number = 0;
public constructor(name: string, age: number) {
super(name, age);
}
}
const man = new Human('Alice', 18);
// -> Constructor of class 'Human' is protected and only accessible within the class declaration.
Кроме того, мы также можем напрямую поставить модификатор в параметры конструктора, например:
class Human {
// public name: string;
// private age: number;
public constructor(public name: string, private age: number) {
this.name = name;
this.age = age;
}
}
const man = new Human('tom', 20);
console.log(man.name); // -> tom
console.log(man.age);
// -> Property 'age' is private and only accessible within class 'Human'.
3. Сигнатуры интерфейса и конструктора
Когда у нас в проекте много разных классов и между этими классами может быть какая-то общность, чтобы описать эту общность, мы можем извлечь ее в интерфейс для централизованного обслуживания и использоватьimplements
ключевое слово для реализации этого интерфейса, пример выглядит следующим образом:
interface IHuman {
name: string;
age: number;
walk(): void;
}
class Human implements IHuman {
public constructor(public name: string, public age: number) {
this.name = name;
this.age = age;
}
walk(): void {
console.log('I am walking...');
}
}
Приведенный выше код гладко проходит этап компиляции, но мы замечаем, что вHuman
класс содержитconstructor
конструктор, если мы хотим определить сигнатуру для этого конструктора в интерфейсе и позволитьHuman
класс для реализации этого интерфейса и посмотрите, что произойдет:
interface HumanConstructor {
new (name: string, age: number);
}
class Human implements HumanConstructor {
public constructor(public name: string, public age: number) {
this.name = name;
this.age = age;
}
walk(): void {
console.log('I am walking...');
}
}
// -> Class 'Human' incorrectly implements interface 'HumanConstructor'.
// -> Type 'Human' provides no match for the signature 'new (name: string, age: number): any'.
Однако TypeScript скомпилируется с ошибкой, сообщая нам, что реализация неверна.HumanConstructor
Интерфейс, это связано с тем, что когда класс реализует интерфейс, компилируется и проверяется только экземплярная часть, а статическая часть класса не проверяется компилятором. Итак, здесь мы попробуем другой способ напрямую манипулировать статической частью класса, пример выглядит следующим образом:
interface HumanConstructor {
new (name: string, age: number);
}
interface IHuman {
name: string;
age: number;
walk(): void;
}
class Human implements IHuman {
public constructor(public name: string, public age: number) {
this.name = name;
this.age = age;
}
walk(): void {
console.log('I am walking...');
}
}
// 定义一个工厂方法
function createHuman(constructor: HumanConstructor, name: string, age: number): IHuman {
return new constructor(name, age);
}
const man = createHuman(Human, 'tom', 18);
console.log(man.name, man.age); // -> tom 18
В приведенном выше примере путем дополнительного создания фабричного методаcreateHuman
И передать конструктор в качестве первого параметра, когда мы вызываемcreateHuman(Human, 'tom', 18)
Компилятор проверит, соответствует ли первый параметрHumanConstructor
Подпись конструктора интерфейса.
4. Заявление о слиянии
Наиболее распространенным типом слияния в декларативном слиянии является интерфейс, поэтому вот некоторые распространенные методы слияния, начиная с интерфейса.
4.1 Объединение интерфейсов
Пример кода выглядит следующим образом:
interface A {
name: string;
}
interface A {
age: number;
}
// 等价于
interface A {
name: string;
age: number;
}
const a: A = {name: 'tom', age: 18};
Метод слияния интерфейсов относительно прост для понимания, то есть объявляется несколько интерфейсов с одним и тем же именем, и каждый интерфейс содержит разные объявления атрибутов. Наконец, эти объявления атрибутов из нескольких интерфейсов будут объединены в один и тот же интерфейс.
Примечание: Все члены, не являющиеся функциями, в интерфейсах с одинаковыми именами должны быть уникальными.Если они не уникальны, они должны быть одного типа, иначе компилятор сообщит об ошибке. Для функций-членов интерфейс с тем же именем, объявленный позже, перезапишет интерфейс с тем же именем, объявленный ранее, то есть функция в интерфейсе с тем же именем, объявленная позже, эквивалентна перегрузке и имеет более высокий приоритет.
4.2 Объединение функций
Объединение функций можно просто понимать как перегрузку функций, то есть определение нескольких функций с одним и тем же именем с разными типами параметров или возвращаемыми значениями разных типов одновременно, пример кода выглядит следующим образом:
// 函数定义
function foo(x: number): number;
function foo(x: string): string;
// 函数具体实现
function foo(x: number | string): number | string {
if (typeof x === 'number') {
return (x).toFixed(2);
}
return x.substring(0, x.length - 1);
}
В приведенном выше примере мы имеемfoo
Функция определяется несколько раз. Каждый раз тип параметра функции отличается, и тип возвращаемого значения отличается. Последний раз - это конкретная реализация функции. В реализации, только когда она совместима со всеми предыдущими определениями, компилятор не сообщит об ошибке.
Примечание. Компилятор TypeScript сначала будет сопоставлять определение функции с самого начала, поэтому, если существует отношение включения между несколькими определениями функций, вам необходимо сначала указать наиболее точное определение функции, иначе оно никогда не будет сопоставлено.
4.3 Объединения псевдонимов типов
Объединение псевдонимов типов отличается от слияния интерфейсов.Псевдоним типа не создает новый тип, а только создает новый псевдоним для ссылки на несколько типов.实现(implements)
и继承(extends)
, пример следующий:
type HumanProperty = {
name: string;
age: number;
gender: number;
};
type HumanBehavior = {
eat(): void;
walk(): void;
}
type Human = HumanProperty & HumanBehavior;
let woman: Human = {
name: 'tom',
age: 18,
gender: 0,
eat() {
console.log('I can eat.');
},
walk() {
console.log('I can walk.');
}
}
class HumanComponent extends Human {
constructor(public name: string, public age: number, public gender: number) {
this.name = name;
this.age = age;
this.gender = gender;
}
eat() {
console.log('I can eat.');
}
walk() {
console.log('I can walk.');
}
}
// -> 'Human' only refers to a type, but is being used as a value here.
5. запрос ключа индекса
на машинописном языкеkeyof
Вроде как в JSObject.keys()
метод, но разница в том, что первый просматривает индекс строки в типе, а второй просматривает имя ключа в объекте. Пример выглядит следующим образом:
interface Rectangle {
x: number;
y: number;
width: number;
height: number;
}
type keys = keyof Rectangle;
// 等价于
type keys = "x" | "y" | "width" | "height";
// 这里使用了泛型,强制要求第二个参数的参数名必须包含在第一个参数的所有字符串索引中
function getRectProperty<T extends object, K extends keyof T>(rect: T, property: K): T[K] {
return rect[property];
}
let rect: Rectangle = {
x: 50,
y: 50,
width: 100,
height: 200
};
console.log(getRectProperty(rect, 'width')); // -> 100
console.log(getRectProperty(rect, 'notExist'));
// -> Argument of type '"notExist"' is not assignable to parameter of type '"width" | "x" | "y" | "height"'.
В приведенном выше примере мы используемkeyof
чтобы ограничить имена параметров функцииproperty
должен быть включен в типRectangle
Из всех строковых индексов , если он не включен, компилятор сообщит об ошибке, которую можно использовать для определения того, неправильно ли написано имя свойства объекта во время компиляции.
6. Частичные необязательные атрибуты
В некоторых случаях, когда мы хотим, чтобы все свойства типа не требовались и существовали только при определенных условиях, мы можем использоватьPartial
чтобы пометить все свойства объявленного типа как необязательные, как в следующем примере:
// 该类型已内置在TypeScript中
type Partial<T> = {
[P in keyof T]?: T[P]
};
interface Rectangle {
x: number;
y: number;
width: number;
height: number;
}
type PartialRectangle = Partial<Rectangle>;
// 等价于
type PartialRectangle = {
x?: number;
y?: number;
width?: number;
height?: number;
}
let rect: PartialRectangle = {
width: 100,
height: 200
};
В приведенном выше примере, поскольку мы используемPartial
Отмечает все свойства как необязательные, поэтому в конечном итогеrect
Хотя объект содержит толькоwidth
иheight
свойства, но компилятор по-прежнему не сообщает об ошибке.Когда мы не можем четко определить, какие свойства содержатся в объекте, мы можем передатьPartial
объявить.
7. Выбор части
В некоторых сценариях приложений нам может понадобиться извлечь подтип из объявленного типа, а подтип содержит некоторые или все свойства супертипа.В этом случае мы можем использоватьPick
Для этого пример кода выглядит следующим образом:
// 该类型已内置在TypeScript中
type Pick<T, K extends keyof T> = {
[P in K]: T[P]
};
interface User {
id: number;
name: string;
age: number;
gender: number;
email: string;
}
type PickUser = Pick<User, "id" | "name" | "gender">;
// 等价于
type PickUser = {
id: number;
name: string;
gender: number;
};
let user: PickUser = {
id: 1,
name: 'tom',
gender: 1
};
В приведенном выше примере, поскольку нас интересует толькоuser
в объектеid
,name
иgender
Существует ли оно, другие свойства четко не указаны, поэтому мы можем использоватьPick
отUser
Интересующие нас свойства выбираются из интерфейса, а проверки компиляции других свойств игнорируются.
8. никогда не будет существовать
never
Представляет тип никогда не существующих значений, таких как генерация исключений в функциях или бесконечные циклы,never
Тип может быть подтипом любого типа и присваиваться любому типу, но, наоборот, ни один тип не может использоваться в качестве подтипа.never
Подтип типа, например:
// 函数抛出异常
function throwError(message: string): never {
throw new Error(message);
}
// 函数自动推断出返回值为never类型
function reportError(message: string) {
return throwError(message);
}
// 无限循环
function loop(): never {
while(true) {
console.log(1);
}
}
// never类型可以是任何类型的子类型
let n: never;
let a: string = n;
let b: number = n;
let c: boolean = n;
let d: null = n;
let e: undefined = n;
let f: any = n;
// 任何类型都不能赋值给never类型
let a: string = '123';
let b: number = 0;
let c: boolean = true;
let d: null = null;
let e: undefined = undefined;
let f: any = [];
let n: never = a;
// -> Type 'string' is not assignable to type 'never'.
let n: never = b;
// -> Type 'number' is not assignable to type 'never'.
let n: never = c;
// -> Type 'true' is not assignable to type 'never'.
let n: never = d;
// -> Type 'null' is not assignable to type 'never'.
let n: never = e;
// -> Type 'undefined' is not assignable to type 'never'.
let n: never = f;
// -> Type 'any' is not assignable to type 'never'.
9. Исключить исключение атрибута
иPick
Напротив,Pick
используется для выбора атрибутов, о которых нам нужно заботиться, иExclude
Используется для исключения свойств, о которых нам не нужно заботиться, примеры следующие:
// 该类型已内置在TypeScript中
// 这里使用了条件类型(Conditional Type),和JS中的三目运算符效果一致
type Exclude<T, U> = T extends U ? never : T;
interface User {
id: number;
name: string;
age: number;
gender: number;
email: string;
}
type keys = keyof User; // -> "id" | "name" | "age" | "gender" | "email"
type ExcludeUser = Exclude<keys, "age" | "email">;
// 等价于
type ExcludeUser = "id" | "name" | "gender";
В приведенном выше примере мы передаемExcludeUser
пройти в том, что нам не нужно заботиться оage
иemail
Атрибуты,Exclude
Это поможет нам удалить ненужные атрибуты и оставить атрибуты позади.id
,name
иgender
Это то имущество, о котором мы должны заботиться. Вообще говоря,Exclude
Редко используется отдельно, может комбинироваться с другими типами для достижения более сложных и полезных функций.
10. Пропустить атрибут игнорируется
В предыдущем использовании мы использовалиExclude
Чтобы устранить другие нежелательные свойства, но в приведенных выше примерах метод связи высок, и когда есть любой другой тип, необходимо обрабатывать ту же логику, поэтому мы будем дополнительно упаковывать его, скрывать эти основные детали обработки, только внешнее воздействие на общедоступный интерфейс, примеры следующие:
// 使用Pick和Exclude组合实现
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
interface User {
id: number;
name: string;
age: number;
gender: number;
email: string;
}
// 表示忽略掉User接口中的age和email属性
type OmitUser = Omit<User, "age" | "email">;
// 等价于
type OmitUser = {
id: number;
name: string;
gender: number;
};
let user: OmitUser = {
id: 1,
name: 'tom',
gender: 1
};
В приведенном выше примере нам нужно игнорироватьUser
в интерфейсеage
иemail
свойства, вам нужно только передать имя интерфейса и свойстваOmit
То есть то же самое верно и для других типов, что значительно улучшает масштабируемость типа и облегчает повторное использование.
Суммировать
Резюме В этой статье несколько советов по TypeScript, если они найдены в нашем проекте TypeScript, есть много мест с общим объявлением типа, то его можно использовать в тексте нескольких методов для его оптимизации, чтобы улучшить и увеличить код, поддерживаемый и возможность повторного использования. Раньше у автора не было много возможностей использовать TypeScript, поэтому в последнее время также изучайте как резюме, если у вас есть неправильное место текста, также хотите иметь возможность исправить меня в области комментариев.
общаться
Если вы считаете, что содержание этой статьи полезно для вас, не могли бы вы сделать мне одолжение и обратить внимание на публичный аккаунт автора [внешний интерфейс], каждую неделю я буду стараться создавать галантерею передовых технологий.После подписки на официальный аккаунт вы можете пригласить вас присоединиться к группе обмена передовыми технологиями.Мы можем общаться друг с другом и вместе добиваться прогресса.
Статья обновлена доБлог на гитхабе, Если вы считаете, что статья приемлема, добро пожаловать!
Один из ваших лайков заслуживает моих дополнительных усилий!
Вырастая перед лицом невзгод, только постоянно учась, вы можете стать лучшей версией себя и поощрять себя!