Typescript: как сопоставить объект с типом?

Предположим, что у меня есть объект, содержащий некоторые данные. Я хочу создать общий преобразователь (соответственно, только функцию - я не хочу постоянно создавать экземпляр нового класса) для всех типов, которые можно использовать следующим образом: this.responseMapper.map<CommentDTO>(data);

Он должен просто взять все свойства из данного типа и сопоставить с ним данные. Что я пробовал до сих пор:

public map<T>(values: any): T {
    const instance = new T();

    return Object.keys(instance).reduce((acc, key) => {
        acc[key] = values[key];
        return acc;
    }, {}) as T;
}

new T(); выдаст ошибку: 'T' only refers to a type, but is being used as a value here.

Как правильно это сделать?


person sandrooco    schedule 09.01.2018    source источник
comment
Если вы добавите параметр type: typeof T и вызовете new type(), он скомпилируется?   -  person cbr    schedule 09.01.2018
comment
Нет, это не так, и нет, на самом деле это не дубликат, потому что я не хочу постоянно создавать экземпляры новых классов картографов.   -  person sandrooco    schedule 09.01.2018
comment
Понятно, спасибо за разъяснение. Фраза создавала впечатление, что это именно то, что вы пытались сделать. Если вы пытаетесь просто отфильтровать ключи, которые не относятся к ключам типа, некоторые функциональные библиотеки называют эту операцию pick.   -  person cbr    schedule 09.01.2018
comment
Так ты не мог бы убрать флаг?   -  person sandrooco    schedule 09.01.2018
comment
Я могу проголосовать за повторное открытие так же, как могу проголосовать за закрытие. Я сделаю это. Вы можете уточнить свой вопрос, отредактировав его, что поместит вопрос в очередь повторного открытия.   -  person cbr    schedule 09.01.2018


Ответы (1)


Вам нужно передать конструктор типа в метод. Typescript стирает дженерики во время выполнения до T неизвестного во время выполнения. Также я бы ужесточил values a bti, чтобы разрешить передачу только членов T. Это можно сделать с помощью Partial<T>

public map<T>(values: Partial<T>, ctor: new () => T): T {
    const instance = new ctor();

    return Object.keys(instance).reduce((acc, key) => {
        acc[key] = values[key];
        return acc;
    }, {}) as T;
 }

Применение:

class Data {
    x: number = 0; // If we don't initialize the function will not work as keys will not return x
}

mapper.map({ x: 0 }, Data)
person Titian Cernicova-Dragomir    schedule 09.01.2018
comment
Это имеет смысл - если я зарегистрирую instance, я не увижу никаких его свойств? Как работает синтаксис `new() =› T`? Любые документы по этой теме? - person sandrooco; 09.01.2018
comment
Все зависит от того, как был определен этот класс. Если вы просто объявите свойства, вы не увидите никаких значений во время выполнения, пока они не будут назначены. new ()=> T является сигнатурой конструктора и будет выполнять конструктор класса. в приведенном выше примере это было бы эквивалентно произнесению new Data(). - person Titian Cernicova-Dragomir; 09.01.2018
comment
Отредактировал код для инициализации x, чтобы подчеркнуть необходимость инициализации, а не просто объявления поля. - person Titian Cernicova-Dragomir; 09.01.2018
comment
Спасибо за отличное объяснение! - person sandrooco; 09.01.2018