Я пытаюсь создать новый объект параметра типа в моем универсальном классе. В моем классе у View
меня есть 2 списка объектов универсального типа, переданных в качестве параметров типа, но когда я пытаюсь создать new TGridView()
, TypeScript говорит:
Не удалось найти символ TGridView
Это код:
module AppFW {
// Represents a view
export class View<TFormView extends FormView, TGridView extends GridView> {
// The list of forms
public Forms: { [idForm: string]: TFormView; } = {};
// The list of grids
public Grids: { [idForm: string]: TGridView; } = {};
public AddForm(formElement: HTMLFormElement, dataModel: any, submitFunction?: (e: SubmitFormViewEvent) => boolean): FormView {
var newForm: TFormView = new TFormView(formElement, dataModel, submitFunction);
this.Forms[formElement.id] = newForm;
return newForm;
}
public AddGrid(element: HTMLDivElement, gridOptions: any): GridView {
var newGrid: TGridView = new TGridView(element, gridOptions);
this.Grids[element.id] = newGrid;
return newGrid;
}
}
}
Могу ли я создавать объекты из универсального типа?
источник
new()
также необходимо - или более общий:type: {new(...args : any[]): T ;}
{ new(): T ;}
? Мне трудно выучить эту часть.ClassA<T>
и я расширяю егоClassB extends ClassA<MyClass>
, я также должен передать его,new () => T = MyClass
иначе ни одно из этих решений не сработает.Вся информация о типах стирается на стороне JavaScript, и поэтому вы не можете обновлять T, как @Sohnee, но я бы предпочел, чтобы типизированный параметр передавался в конструктор:
class A { } class B<T> { Prop: T; constructor(TCreator: { new (): T; }) { this.Prop = new TCreator(); } } var test = new B<A>(A);
источник
export abstract class formBase<T> extends baseClass { protected item = {} as T; }
Его объект сможет получить любой параметр, однако тип T является всего лишь ссылкой на машинописный текст и не может быть создан через конструктор. То есть он не будет создавать никаких объектов класса.
источник
T
, поэтому любые геттеры / сеттеры, определенные в,T
могут не работать.class Foo{ method() { return true; }
, приведение {} к T не даст вам этого метода!Я знаю поздно, но ответ @TadasPa можно немного изменить, используя
TCreator: new() => T
вместо того
TCreator: { new (): T; }
итак результат должен выглядеть так
class A { } class B<T> { Prop: T; constructor(TCreator: new() => T) { this.Prop = new TCreator(); } } var test = new B<A>(A);
источник
Я пытался создать общий экземпляр из базового класса. Ни один из приведенных выше примеров не помог мне, поскольку для вызова фабричного метода требовался конкретный тип.
После некоторого исследования этого и неспособного найти решение в Интернете, я обнаружил, что это, похоже, работает.
protected activeRow: T = {} as T;
Кусочки:
activeRow: T = {} <-- activeRow now equals a new object...
...
as T; <-- As the type I specified.
Все вместе
export abstract class GridRowEditDialogBase<T extends DataRow> extends DialogBase{ protected activeRow: T = {} as T; }
Тем не менее, если вам нужен реальный экземпляр, вы должны использовать:
export function getInstance<T extends Object>(type: (new (...args: any[]) => T), ...args: any[]): T { return new type(...args); } export class Foo { bar() { console.log("Hello World") } } getInstance(Foo).bar();
Если у вас есть аргументы, вы можете использовать.
export class Foo2 { constructor(public arg1: string, public arg2: number) { } bar() { console.log(this.arg1); console.log(this.arg2); } } getInstance(Foo, "Hello World", 2).bar();
источник
Вот что я делаю, чтобы сохранить информацию о типе:
class Helper { public static createRaw<T>(TCreator: { new (): T; }, data: any): T { return Object.assign(new TCreator(), data); } public static create<T>(TCreator: { new (): T; }, data: T): T { return this.createRaw(TCreator, data); } } ... it('create helper', () => { class A { public data: string; } class B { public data: string; public getData(): string { return this.data; } } var str = "foobar"; var a1 = Helper.create<A>(A, {data: str}); expect(a1 instanceof A).toBeTruthy(); expect(a1.data).toBe(str); var a2 = Helper.create(A, {data: str}); expect(a2 instanceof A).toBeTruthy(); expect(a2.data).toBe(str); var b1 = Helper.createRaw(B, {data: str}); expect(b1 instanceof B).toBeTruthy(); expect(b1.data).toBe(str); expect(b1.getData()).toBe(str); });
источник
Я использую это:
let instance = <T>{};
обычно он работает EDIT 1:export class EntityCollection<T extends { id: number }>{ mutable: EditableEntity<T>[] = []; immutable: T[] = []; edit(index: number) { this.mutable[index].entity = Object.assign(<T>{}, this.immutable[index]); } }
источник
T
, а просто создаст пустой объект, который, по мнению TypeScript, имеет типT
. Возможно, вы захотите пояснить свой ответ более подробно.Не совсем отвечаю на вопрос, но для таких проблем есть хорошая библиотека: https://github.com/typestack/class-transformer (хотя для общих типов это не сработает, поскольку их на самом деле не существует во время выполнения (здесь вся работа выполняется с именами классов (которые являются конструкторами классов)))
Например:
import {Type, plainToClass, deserialize} from "class-transformer"; export class Foo { @Type(Bar) public nestedClass: Bar; public someVar: string; public someMethod(): string { return this.nestedClass.someVar + this.someVar; } } export class Bar { public someVar: string; } const json = '{"someVar": "a", "nestedClass": {"someVar": "B"}}'; const optionA = plainToClass(Foo, JSON.parse(json)); const optionB = deserialize(Foo, json); optionA.someMethod(); // works optionB.someMethod(); // works
источник
Я опаздываю на вечеринку, но так у меня получилось. Для массивов нам нужно проделать несколько хитростей:
public clone<T>(sourceObj: T): T { var cloneObj: T = {} as T; for (var key in sourceObj) { if (sourceObj[key] instanceof Array) { if (sourceObj[key]) { // create an empty value first let str: string = '{"' + key + '" : ""}'; Object.assign(cloneObj, JSON.parse(str)) // update with the real value cloneObj[key] = sourceObj[key]; } else { Object.assign(cloneObj, []) } } else if (typeof sourceObj[key] === "object") { cloneObj[key] = this.clone(sourceObj[key]); } else { if (cloneObj.hasOwnProperty(key)) { cloneObj[key] = sourceObj[key]; } else { // insert the property // need create a JSON to use the 'key' as its value let str: string = '{"' + key + '" : "' + sourceObj[key] + '"}'; // insert the new field Object.assign(cloneObj, JSON.parse(str)) } } } return cloneObj; }
Используйте это так:
let newObj: SomeClass = clone<SomeClass>(someClassObj);
Его можно улучшить, но он работает для моих нужд!
источник
Я добавляю это по запросу, а не потому, что считаю, что это напрямую решает вопрос. Мое решение включает в себя табличный компонент для отображения таблиц из моей базы данных SQL:
export class TableComponent<T> { public Data: T[] = []; public constructor( protected type: new (value: Partial<T>) => T ) { } protected insertRow(value: Partial<T>): void { let row: T = new this.type(value); this.Data.push(row); } }
Чтобы использовать это, предположим, что у меня есть представление (или таблица) в моей базе данных VW_MyData, и я хочу использовать конструктор моего класса VW_MyData для каждой записи, возвращаемой из запроса:
export class MyDataComponent extends TableComponent<VW_MyData> { public constructor(protected service: DataService) { super(VW_MyData); this.query(); } protected query(): void { this.service.post(...).subscribe((json: VW_MyData[]) => { for (let item of json) { this.insertRow(item); } } } }
Причина, по которой это желательно вместо простого присвоения возвращаемого значения Data, заключается в том, что у меня есть код, который применяет преобразование к некоторому столбцу VW_MyData в его конструкторе:
export class VW_MyData { public RawColumn: string; public TransformedColumn: string; public constructor(init?: Partial<VW_MyData>) { Object.assign(this, init); this.TransformedColumn = this.transform(this.RawColumn); } protected transform(input: string): string { return `Transformation of ${input}!`; } }
Это позволяет мне выполнять преобразования, проверки и все остальное для всех моих данных, поступающих в TypeScript. Надеюсь, это поможет кому-то понять.
источник
Вот пример, если вам нужны параметры в конструкторе:
class Sample { public innerField: string; constructor(data: Partial<Sample>) { this.innerField = data.innerField; } } export class GenericWithParams<TType> { public innerItem: TType; constructor(data: Partial<GenericWithParams<TType>>, private typePrototype: new (i: Partial<TType>) => TType) { this.innerItem = this.factoryMethodOnModel(data.innerItem); } private factoryMethodOnModel = (item: Partial<TType>): TType => { return new this.typePrototype(item); }; } const instance = new GenericWithParams<Sample>({ innerItem : { innerField: 'test' }}, Sample);
источник