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

У меня есть класс es6 User и глобальная функция map(), приведенная ниже:

class  User {
  constructor(public name: string) {}
}

const map = <T, R>(project: (value: T) => R) => {}

Вместо того, чтобы писать следующее:

map((value) => new User(value))

Я хочу (каким-то образом) напишите что-то вроде:

map(new User)

Я не уверен, возможно ли это или нет.

Ответы [ 6 ]

0 голосов
/ 03 января 2019

Если вы хотите универсальное решение и не можете изменять классы, вы можете использовать функцию более высокого порядка:

function make(klass) {
    return (...params) => new klass(...params);
}

// this:
map((value) => new User(value));

// becomes this:
map(make(User));
0 голосов
/ 31 декабря 2018

Это хорошо известная «проблема» в обсуждении «oop vs fp» в JS - конструкторы классов против конструкторов функций

, поскольку классам es6 требуется оператор new, это невозможночтобы написать что-то вроде map(new User)

, вам нужна оболочка для конструктора класса, который создает экземпляры с помощью вызова функции.ИМО, подход @ baboo - это путь

class MyClass {
  // ...

  static create(...args) {
    return new MyClass(...args)
  }
}
const a = new MyClass('hello', [])
const b = MyClass.create('world', 123])

Вы можете прочитать больше о проблемах new здесь .

, checkout daggy - Библиотека для создания теговых конструкторов

0 голосов
/ 30 декабря 2018

Шаблон, который вы описываете, называется областным безопасным конструктором .Это может быть реализовано путем перегрузки конструктора, чтобы он работал с и без ключевого слова new.

interface User {
  name: string;
}

interface UserConstructor {
  new (name: string): User;
  (name: string): User;
}

Тот же трюк используется для глобальных объектов, таких как Array или Date.

Нам необходимо выяснить, использовалось ли ключевое слово new:

const User = function (this: User | void, name: string): User {
  if (!(this instanceof User)) {
    return new User(name);
  }

  this.name = name;
  return this;
} as UserConstructor;

Ваш класс только что стал new -агностическим.

console.log(
  new User('Bob'),
  User('Alice'),
);

Что позволило нам написать:

['Alice', 'Bob'].map(User); // $ExpectType User[]
0 голосов
/ 28 декабря 2018

Вы можете добавить проверку с помощью new.target, если функция вызывается без нового и вызывается, а затем функция с помощью new.

function Person(name) {
    if (!new.target) return new Person(...arguments);
    this.name = name;
}

var names = ['Jane', 'Dan', 'Grace', 'Paul'],
    instances = names.map(Person);

console.log(instances);
0 голосов
/ 28 декабря 2018

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

class User {
  static createUser(value) {
    return new User(value)
  }
}

И затем используйте:

map(User.createUser)
0 голосов
/ 28 декабря 2018

Вы не можете сделать это напрямую.Если вы управляете целевой функцией (т. Е. Она не является стандартной map функцией), вы можете использовать ее вместо конструктора вместо функции:

class User { constructor(private id: number) { }}
function map<TIn, T>(value: TIn, ctor: new (a: TIn) => T): T{
    return new ctor(value)
}
map(10, User)

Другим более гибким решением является использование вспомогательной функции, которая преобразуетконструктор в нужную функцию, хотя она не намного короче оригинальной версии:

class User { constructor(private id: number) { }}
function ctor<TIn, T>(ctor: new (a: TIn) => T): (value: TIn) => T{
    return value => new ctor(value)
}
[10, 11].map(ctor(User));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...