Как добавить «новые» ограничения для универсального параметра в машинописи? - PullRequest
0 голосов
/ 09 октября 2018

Я уже знаю, как добавить ограничение «newable» (т.е. имеет конструктор) для аргументов функции (например, аргумент для функции foo ниже), но эта же техника не применяется к параметрам универсального типа.

Почему это и как это исправить?

enter image description here

type NoParameterCtor<T> = { new(): T }

function foo<T>(ctor: NoParameterCtor<T>) { }

interface Bar<T extends NoParameterCtor<T>> { }

class Zoo { }

foo(Zoo) 
// no compiler error

class Zar implements Bar<Zoo> { }
// Type 'Zoo' does not satisfy the constraint 'NoParameterCtor<Zoo>'

1 Ответ

0 голосов
/ 10 октября 2018

Как уже упоминалось в комментариях, T extends NoParameterCtor<T> - это необычное ограничение, которое означает, что "T - это конструктор, который создает новые экземпляры сам по себе".Если вы не пытаетесь описать самовоспроизводящиеся конструкторы, это не то, что вы имеете в виду.

Если вы просто хотите, чтобы T было «чем-то новым», вам не нужно заботиться о типе экземпляра.Предполагая, что вы используете TS3.0 или новее, вы можете использовать unknown для обозначения любого типа, хотя вы также можете использовать any.Поэтому, возможно, вы хотите, чтобы Bar было

interface Bar<T extends NoParameterCtor<unknown>> { }

Следующее по-прежнему не будет работать, хотя:

class Zar implements Bar<Zoo> { } // error! 
// Zoo does not satisfy the constraint NoParameterCtor<unknown>

Это потому, что тип Zoo не является новым;это тип экземпляра класса Zoo.Я не знаю, если вас смущает разница между именованными значениями и именованными типами в TypeScript, но вы в хорошей компании, если это так.Вкратце, class Zoo {} вводит тип с именем Zoo, который является типом экземпляров класса, и значение с именем Zoo, который является конструктором такогоэкземпляров.И тип значения Zoo не является типом Zoo.Чтобы сослаться на тип значения конструктора Zoo, вместо него необходимо использовать typeof Foo:

class Zar implements Bar<typeof Zoo> { } // okay

Также я предполагаю, что вы удалили содержимое Bar, Zar иZoo потому что они здесь не актуальны.Но, чтобы быть ясным, пустые интерфейсы соответствуют практически всем, потому что TypeScript использует структурную типизацию .Если Bar требуется доступ к типу экземпляра T, то вы можете использовать псевдоним встроенной библиотеки InstanceType<>, чтобы получить его:

interface Bar<T extends NoParameterCtor<unknown>> {
   theConstructor: T,
   theInstance: InstanceType<T>
}

class Zar implements Bar<typeof Zoo> { 
  theConstructor = Zoo; // the constructor
  theInstance = new Zoo(); // an instance
}

Надеюсь, чтопомогает.Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...