জেনেরিক ক্লাসে টাইপ পরামিতি থেকে একটি নতুন অবজেক্ট তৈরি করুন


144

আমি আমার জেনেরিক ক্লাসে টাইপ প্যারামিটারের একটি নতুন অবজেক্ট তৈরি করার চেষ্টা করছি। আমার ক্লাসে আমার Viewকাছে জেনেরিক ধরণের অবজেক্টের 2 টি তালিকা টাইপ প্যারামিটার হিসাবে পাস হয়েছে, তবে আমি যখন বানানোর চেষ্টা করব তখন new 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;
        }
    }
}

আমি কি জেনেরিক টাইপ থেকে অবজেক্ট তৈরি করতে পারি?

উত্তর:


95

সংকলিত জাভাস্ক্রিপ্টে সমস্ত ধরণের তথ্য মুছে ফেলা হয়েছে, আপনি 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();

144

জেনেরিক কোডের মধ্যে একটি নতুন অবজেক্ট তৈরি করতে, আপনাকে তার নির্মাণকারীর ক্রিয়া দ্বারা প্রকারটি উল্লেখ করতে হবে। সুতরাং এটি লেখার পরিবর্তে:

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

এই প্রশ্নটি দেখুন: শ্রেণি আর্গুমেন্টের সাথে জেনেরিক ধরণের অনুক্রম


35
কিছুটা দেরী (তবে দরকারী) মন্তব্য - আপনার নির্মাণকারীর যদি new()type: {new(...args : any[]): T ;}
আরোগুলি

1
: @Yoda IActivatable একটি স্ব নির্মিত ইন্টারফেস, অন্যান্য প্রশ্ন দেখতে পাবেন stackoverflow.com/questions/24677592/...
জেমি

1
এটি কীভাবে অনুমান করা উচিত { new(): T ;}। এই অংশটি শিখতে আমার খুব কষ্ট হচ্ছে।
এবিটকড

1
এটির (এবং অন্যান্য সমস্ত সমাধান এখানে) জেনেরিক নির্দিষ্ট করার জন্য আপনাকে ক্লাসে পাস করতে হবে। এটি হ্যাকি এবং অনর্থক। এর অর্থ যদি আমার একটি বেস শ্রেণি থাকে ClassA<T>এবং এটি প্রসারিত হয় তবে ClassB extends ClassA<MyClass>আমাকে new () => T = MyClassএই সমাধানগুলির মধ্যেও পাস করতে হবে না বা কোনওটিই কাজ করে না।
অ্যান্ড্রুবেনজামিন

@ অ্যান্ড্রুবেঞ্জমিন আপনার পরামর্শ কি তাহলে? কিছু শুরু করার চেষ্টা করা হচ্ছে না (আসলে শিখতে চাইছে) তবে একে অপ্রত্যাশিত এবং অপ্রয়োজনীয় infers বলার সাথে আপনি ভাগ করে নিচ্ছেন না এমন অন্য কোনও উপায় জানেন :)
পেরি

37

সমস্ত ধরণের তথ্য জাভাস্ক্রিপ্টের পাশেই মুছে ফেলা হয়েছে এবং অতএব আপনি সোনি যেমন বলেছেন যে আপনি টি নতুন করতে পারবেন না, তবে আমি টাইপ পরামিতিটি কনস্ট্রাক্টরের কাছে দিয়ে যেতে পছন্দ করব:

class A {
}

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

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

12
export abstract class formBase<T> extends baseClass {

  protected item = {} as T;
}

এর অবজেক্টটি যে কোনও প্যারামিটার পেতে সক্ষম হবে, তবে টাইপ টি কেবল একটি টাইপস্ক্রিপ্ট রেফারেন্স এবং কোনও কনস্ট্রাক্টরের মাধ্যমে তৈরি করা যায় না। অর্থাত্ এটি কোনও শ্রেণীর অবজেক্ট তৈরি করবে না।


6
সাবধান , এটি কাজ করতে পারে তবে ফলস্বরূপ অবজেক্টটি টাইপের হয় না T, সুতরাং সংজ্ঞায়িত যে কোনও গেটার / সেটটার Tকাজ করতে পারে না।
ড্যানিয়েল ওরেমিও

@ ড্যানিয়েলআরমেও কি বোঝাতে চান? এর মানে কি বোঝাতে চাচ্ছো? আমার কোডটি এই স্নিপেট ব্যবহার করে কাজ করছে বলে মনে হচ্ছে। ধন্যবাদ।
ইস্টেইন

জাভাস্ক্রিপ্ট একটি ব্যাখ্যা করা ভাষা এবং বাস্তু স্ক্রিপ্টটিতে এখনও প্রকার বা শ্রেণীর উল্লেখ নেই। সুতরাং টি টাইপস্ক্রিপ্টের জন্য কেবল একটি রেফারেন্স।
জেল কার্ডোসো

এটি জাভাস্ক্রিপ্টে এমনকি একটি ভুল উত্তর। আপনার যদি একটি থাকে class Foo{ method() { return true; }, তবে} T টি তে কাস্টিং আপনাকে এই পদ্ধতিটি দেবে না!
জেসিকেডেল

8

আমি দেরিতে জানি কিন্তু @ তাদাস্পার উত্তরটি ব্যবহার করে কিছুটা সামঞ্জস্য করা যায়

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

4

আমি বেস ক্লাসের মধ্যে থেকে জেনেরিকটি ইনস্ট্যান্ট করার চেষ্টা করছিলাম। কারখানার পদ্ধতিতে কল করার জন্য উপরের উদাহরণগুলির মধ্যে আমার পক্ষে কোনও কাজ করা হয়নি কারণ তাদের একটি কংক্রিট ধরণের প্রয়োজন ছিল।

এ সম্পর্কে কিছুক্ষণ গবেষণা করার পরে এবং অনলাইনে কোনও সমাধান খুঁজে না পাওয়ার পরে, আমি আবিষ্কার করেছি যে এটি কাজ করে।

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

2
এটি জাভাস্ক্রিপ্টে এমনকি একটি ভুল উত্তর। আপনার যদি ক্লাস Foo {পদ্ধতি থাকে () {সত্য ফিরে আসে; },}} কে টি তে কাস্টিং আপনাকে এই পদ্ধতিটি দেবে না!
জেসিকেডেল

আপনার যদি পদ্ধতি না থাকে তবে আমি কাজ করি। তবে আপনার যদি পদ্ধতিগুলির সাথে কোনও অবজেক্ট থাকে তবে আপনার অবশ্যই কোডটি সবেমাত্র যুক্ত করা উচিত।
খ্রিস্টান প্যাটার

2

টাইপ তথ্য ধরে রাখতে আমি এটিই করি:

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

});

1

আমি এটি ব্যবহার করি: 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]);
  }
}

5
এটি আসলে কোনও নতুন উদাহরণ ইনস্ট্যান্ট করবে না T, এটি কেবল একটি ফাঁকা অবজেক্ট তৈরি করবে যা টাইপস্ক্রিপ্টটি টাইপ বলে মনে করেT । আপনি নিজের উত্তরটি আরও কিছুটা বিশদে ব্যাখ্যা করতে চাইতে পারেন।
স্যান্ডি গিফোর্ড 15

আমি বলেছিলাম এটি সাধারণত কাজ করে। আপনি যেমন বলছেন ঠিক তেমনই। সংকলকটি হাহাকার করছে না এবং আপনার জেনেরিক কোড রয়েছে। আপনি এই উদাহরণটি স্বতঃস্ফূর্ত নির্মাণকারীর প্রয়োজন ছাড়াই ম্যানুয়ালি আপনার পছন্দসই বৈশিষ্ট্য সেট করতে ব্যবহার করতে পারেন।
বোজো

1

প্রশ্নের পুরোপুরি উত্তর না দিয়ে, তবে, এই ধরণের সমস্যার জন্য একটি দুর্দান্ত গ্রন্থাগার রয়েছে: 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

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

এটি উন্নত করা যেতে পারে তবে আমার প্রয়োজনের জন্য কাজ করেছে!


1

আমি এটি অনুরোধের মাধ্যমে যুক্ত করছি, কারণ আমি মনে করি এটি সরাসরি প্রশ্নটি সমাধান করে না। আমার সমাধানটি আমার এসকিউএল ডাটাবেস থেকে সারণী প্রদর্শন করার জন্য একটি টেবিল উপাদান জড়িত:

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

এটি ব্যবহার করার জন্য, ধরে নিই আমার আমার ডেটাবেস ভিডাব্লু_মাইডিটাতে একটি ভিউ (বা টেবিল) আছে এবং আমি আমার ভিউওয়াই_মাইডিটা ক্লাসের কনস্ট্রাক্টরকে প্রতিটি প্রশ্নের জন্য ফিরে আসা প্রতিটি প্রবেশের জন্য আঘাত করতে চাই:

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

কেবলমাত্র ডেটাতে প্রত্যাবর্তিত মান নির্ধারণের তুলনায় এটি কাঙ্ক্ষিত, কারণ আমার কাছে এমন কিছু কোড রয়েছে যা এর নির্মাণকারীর মধ্যে ভিডাব্লু_মাইডিটার কোনও কলামে রূপান্তর প্রযোজ্য:

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}!`;
    }
}

এটি আমাকে টাইপস্ক্রিপ্টে আসা আমার সমস্ত ডেটাতে ট্রান্সফর্মেশন, বৈধতা এবং অন্য যে কোনও কিছু সম্পাদন করতে দেয়। আশা করি এটি কারওর জন্য কিছু অন্তর্দৃষ্টি সরবরাহ করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.