我正在尝试在我的泛型类中创建一个类型参数的新对象。
在我的班级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;
}
}
}
我可以创建泛型类型的对象吗?
答案 0 :(得分:113)
要在通用代码中创建新对象,需要通过其构造函数引用类型。所以不要写这个:
function activatorNotWorking<T extends IActivatable>(type: T): T {
return new T(); // compile error could not find symbol T
}
你需要写下这个:
function activator<T extends IActivatable>(type: { new(): T ;} ): T {
return new type();
}
var classA: ClassA = activator(ClassA);
答案 1 :(得分:63)
由于已编译的JavaScript已删除所有类型信息,因此您无法使用T
来新建对象。
您可以通过将类型传递给构造函数来以非泛型方式执行此操作。
class TestOne {
hi() {
alert('Hi');
}
}
class TestTwo {
constructor(private testType) {
}
getNew() {
return new this.testType();
}
}
var test = new TestTwo(TestOne);
var example = test.getNew();
example.hi();
您可以使用泛型来扩展此示例以收紧类型:
class TestBase {
hi() {
alert('Hi from base');
}
}
class TestSub extends TestBase {
hi() {
alert('Hi from sub');
}
}
class TestTwo<T extends TestBase> {
constructor(private testType: new () => T) {
}
getNew() : T {
return new this.testType();
}
}
//var test = new TestTwo<TestBase>(TestBase);
var test = new TestTwo<TestSub>(TestSub);
var example = test.getNew();
example.hi();
答案 2 :(得分:26)
所有类型信息都在JavaScript方面被删除,因此您不能像@Sohnee状态那样新建T,但我更希望将输入的类型参数传递给构造函数:
class A {
}
class B<T> {
Prop: T;
constructor(TCreator: { new (): T; }) {
this.Prop = new TCreator();
}
}
var test = new B<A>(A);
答案 3 :(得分:8)
export abstract class formBase<T> extends baseClass {
protected item = {} as T;
}
它的对象将能够接收任何参数,但是,类型T只是一个打字稿参考,不能通过构造函数创建。也就是说,它不会创建任何类对象。
答案 4 :(得分:2)
我知道晚了,但是@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);
答案 5 :(得分:1)
我试图从基类中实例化泛型。以上所有示例都不适用于我,因为它们需要具体类型才能调用工厂方法。
经过一段时间的研究,无法在线找到解决方案后,我发现这似乎有效。
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();
答案 6 :(得分:1)
这是我要保留的类型信息:
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);
});
答案 7 :(得分:1)
我参加聚会很晚,但这就是我要工作的方式。对于数组,我们需要做一些技巧:
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);
可以改进,但可以满足我的需求!
答案 8 :(得分:1)
我要根据要求添加它,不是因为我认为它可以直接解决问题。我的解决方案涉及一个表组件,该组件用于显示我的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的所有数据执行转换,验证以及其他操作。希望它能为某人提供一些见识。
答案 9 :(得分:0)
我用这个:let instance = <T>{};
它通常有效
编辑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]);
}
}
答案 10 :(得分:0)
尚未完全回答问题,但是有一个很好的库可以解决此类问题: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
答案 11 :(得分:0)
如果您在构造函数中需要参数,请参见以下示例:
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);
答案 12 :(得分:-2)
在打字稿中,我使用public class A<T>
{
public Data:T = new Object() as T;
}
来解析“单个对象”类型和“对象数组”类型
<img src="C:\Users\ghost\Desktop\Projects\Bagwell\wetransfer-95bb54\IMG_7098.JPG" style="width:80%; margin: 0 auto; height: auto" class="d-block">