![](/img/trans.png)
[英]How to create a new object of type 'T' in generic class in typescript?
[英]Create a new object from type parameter in generic class
我正在嘗試在我的通用 class 中創建一個類型參數的新 object。 在我的 class 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;
}
}
}
我可以從泛型類型創建對象嗎?
要在通用代碼中創建新對象,您需要通過其構造函數來引用類型。 所以,而不是寫這個:
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);
因為編譯后的 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();
所有類型信息都在 JavaScript 端被刪除,因此你不能像 @Sohnee 狀態那樣更新 T,但我更喜歡將類型參數傳遞給構造函數:
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 只是一個打字稿引用,不能通過構造函數創建。 也就是說,它不會創建任何類對象。
我知道晚了,但@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);
});
我是應要求添加的,不是因為我認為它直接解決了問題。 我的解決方案涉及一個表組件,用於顯示我的 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 的所有數據執行轉換、驗證和其他任何操作。 希望它為某人提供一些見解。
我用這個: 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]);
}
}
不能完全回答這個問題,但是,對於這類問題,有一個不錯的庫: 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);
它可以改進,但可以滿足我的需求!
如果您需要在構造函數中使用參數,這是示例:
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);
在Typescript中,我使用Object
來解析“單個對象”類型和“對象數組”類型
public class A<T>
{
public Data:T = new Object() as T;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.