programing

일반 클래스의 형식 매개 변수에서 새 개체 만들기

sourcejob 2023. 4. 4. 21:15
반응형

일반 클래스의 형식 매개 변수에서 새 개체 만들기

일반 클래스에 형식 매개 변수의 새 개체를 만들려고 합니다. 반에서는 ★★★★★★★★★★★★★★★★★★.View, 이 오브젝트 리스트를 작성하려고 2개입니다new TGridView() 과 같이 표시됩니다

'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를 새로 만들 수는 없지만 type 파라미터가 컨스트럭터에 전달되는 것을 선호합니다.

class A {
}

class B<T> {
    Prop: T;
    constructor(TCreator: { new (): T; }) {
        this.Prop = new TCreator();
    }
}

var test = new B<A>(A);

늦은 감이 있지만 @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);
export abstract class formBase<T> extends baseClass {

  protected item = {} as T;
}

개체는 어떤 매개 변수도 수신할 수 있지만 Type T는 형식 설명 참조일 뿐 생성자를 통해 생성할 수 없습니다.즉, 클래스 오브젝트는 생성되지 않습니다.

기본 클래스 내에서 일반을 인스턴스화하려고 했습니다.위의 예들은 공장법을 부르기 위해 콘크리트 타입이 필요했기 때문에 나에게 효과가 없었다.

이것에 대해 한동안 조사해 본 결과, 온라인으로 해결책을 찾을 수 없었던 것을 알 수 있었습니다.

 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);
            }
        }
    }
}

반환된 값을 단순히 데이터에 할당하는 것보다 이것이 바람직한 이유는 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로 들어오는 모든 데이터에 대해 변환, 검증 및 기타 작업을 수행할 수 있습니다.그게 누군가에게 통찰력을 주길 바라.

질문에 대한 답변은 아니지만, 이러한 문제에 대한 좋은 라이브러리가 있습니다.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);

개선은 가능하지만 내 필요에 맞게 작동한다!

나는 이것을 사용한다: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]);
  }
}

다음은 컨스트럭터에 파라미터가 필요한 경우의 예입니다.

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);

언급URL : https://stackoverflow.com/questions/17382143/create-a-new-object-from-type-parameter-in-generic-class

반응형