Я собираюсь перейти с String
на RegExp
, потому что есть складка с String
Я упомяну позже *.
Интерфейс экземпляра (например, RegExp
и JQuery
) обычно представляет тип объекта, в котором может существовать несколько разных экземпляров. Связанный статический интерфейс (например, RegExpConstructor
и JQueryStatic
) обычно представляет тип объекта, который создает или возвращает этих экземпляров; и часто существует только один из этих статических объектов. Таким образом, существует только один RegExpConstructor
объект, который может создавать множество RegExp
объектов, и только один JQueryStatic
объект, который может создавать множество JQuery
объектов.
Одним из распространенных источников путаницы на практике является конфликт имен между значениями и типами . Имя одного статического объекта (например, RegExp
или jQuery
), как правило, совпадает с именем интерфейса экземпляра. Но тип этого статического объекта не является типом интерфейса экземпляра. Таким образом, значение с именем RegExp
во время выполнения имеет тип RegExpConstructor
, а не RegExp
. И значение с именем jQuery
во время выполнения имеет тип JQueryStatic
, а не JQuery
. Это сбивает с толку, но, вероятно, к лучшему, так как позволяет вам говорить во время выполнения, например, x instanceof Y
и во время компиляции, что тип x
равен Y
.
В любом случае, если есть свойство или метод, поведение которого зависит от конкретного экземпляра, оно обычно находится на интерфейсе экземпляра. Если есть какое-либо свойство или метод, поведение которого не зависит от конкретного экземпляра, это обычно находится на статическом интерфейсе.
Интерфейс конструктора - это статический интерфейс, который позволяет вам использовать оператор new
для создания новых экземпляров. В TypeScript это представляется аналогично сигнатуре вызова функции, но с именем new
, например:
type F = (x: string) => number[];
type C = new(x: string) => number[];
Тип F
представляет функцию, которая принимает параметр string
и создает массив number
с, в то время как тип C
представляет конструктор функцию, которая принимает string
параметр и выдает массив number
s:
declare const f: F;
declare const c: C;
const arr1 = f("hey"); // number[]
const oops1 = new f("hey"); // error, f is not newable
const arr2 = new c("hey"); // number[]
const oops2 = c("hey"); // error, c is not callable
Распространен статический интерфейс, который также является интерфейсом конструктора; все class
статические интерфейсы являются интерфейсами конструктора. Но не каждый статический интерфейс является интерфейсом конструктора. Интерфейс JQueryStatic
является примером того, которого нет. Чтобы получить экземпляр JQuery
из объекта JQueryStatic
, вы вызываете его как функцию (именно это означает подпись (query: string): JQuery;
).
В этом и заключается основное различие между парой JQueryStatic
/ JQuery
и парой RegExpConstructor
/ RegExp
и окончание основного ответа на вопрос.
* Вернуться к String
морщинке. Тип с именем String
специально относится к объекту , созданному путем вызова оператора new
в конструкторе String
. Существует также тип с именем string
(с нижним регистром '), который относится к типу данных примитив . Практически все строки, с которыми вы имеете дело, являются такими примитивами типа string
, тогда как String
является относительно необычным объектом-оболочкой , который содержит значение string
. A string
и String
в основном взаимозаменяемы:
const stringPrimitive = "hello"; // type is string
const stringObject = new String("hello"); // type is String
console.log(stringPrimitive+"!"); // "hello!"
console.log(stringObject+"!"); // "hello!"
console.log(stringPrimitive.charAt(4)); // "o"
console.log(stringObject.charAt(4)); // "o"
за исключением случаев, когда они не являются взаимозаменяемыми:
console.log(typeof stringPrimitive); // "string"
console.log(typeof stringObject); // "object"
console.log(stringPrimitive instanceof String); // false
console.log(stringObject instanceof String); // true
Ситуация становится еще более запутанной, когда вы понимаете, что StringConstructor
также может быть вызван как функция и создает примитив string
:
console.log(typeof "hey"); // "string"
console.log(typeof new String("hey")); // "object"
console.log(typeof String("hey")); // "string"
Так что это довольно беспорядок. Правило здесь в значительной степени всегда использовать string
; никогда не используйте String
. И именно поэтому я изменил пример кода с String
на всегда-объект RegExp
, для которого не существует примитивного типа данных (typeof /foo/ === "object"
), который мешал бы.
Хорошо, надеюсь, это поможет. Удачи!