Home > OS >  How to define the types for the properties of a class that extends Array?
How to define the types for the properties of a class that extends Array?

Time:05-05


Defining types for Class-member's in an Extended Array Class


Ive tried writing this question once before and deleted it, because it was difficult to explain my problem, as a consequence; I decided the best way to proceed would be to write a textbook style example. The code below is a pseudo example (Obviously), but a working solution would have real implementation in my work.

I'll Explain a bit more, but first lets look at some code.

Below is a working example; in-fact you don't even need to open your editor as I rewrote it for you in an instance of a TS playground. Click Here if you want to be able to run it, and see the types via a Hover-widget.


/*
---------------("DOCUMENT #1")--------------- */
type OmpaLoompa = {
  name: string,
  work: ()=> string
}

type OmpaLoompas = OmpaLoompa[];


class WillyWonka extends Array{
  constructor(sumOmpaLoompas: OmpaLoompas){
    super();
    Object.assign(this, sumOmpaLoompas);
  }
}

const ompaLoompas = [
  {
    name: 'Frank the Frightened Ompa',
    work: ()=> 'Produced Chocolate'
  },
  {

    name: 'Fran the Frail Loompa',
    work: ()=> 'Produced Carmel'
  },
  {
    name: 'Larry the Lazy Ompa',
    work: ()=> 'Didn\'t Produce Today'
  },
  {
    name: 'Linda the Lovely Loompa',
    work: ()=> 'Produced Wafers'
  }
];
/*


---------------("DOCUMENT #2")--------------- */
const wonkyWilly = new WillyWonka(ompaLoompas);
const ompaLoompaAtZero = wonkyWilly[0];
const ompaLoompaAtTwo = wonkyWilly[2];

console.log(ompaLoompaAtZero); //       <-- TYPE = ANY (I need this to be "type: OmpaLoompa")
console.log(ompaLoompaAtTwo.work()); // <-- TYPE = ANY (I need this to be "type: OmpaLoompa.work")

// EXPECTED OUTPUT:
// { name: 'Frank the Frightened Ompa', work: [Function: work] }
// Didn't Produce Today


SUMMARIZING


  1. In the example above there is a class WillyWonka that extends the Array class.

  2. The classes constructor takes a single argument of a well defined type.

  3. Then Object.assign(...) is used to add the iteratable objects from the constructors argument, as properties to the class, so the properties can be accessed, and iterated through using the extended array class.


Here's My Problem


Maybe I am writing the class wrong, to be honest I don't really know if this is the best way to go about defining a custom array object. It seems to work for all intents and purposes, except for one — and being that it is TypeScript, its sort of a big one — Type Inference. I was hoping that the TSC could infer the types so that when I import the WillyWonka class from one document to the next, it would know that willyWonka[0] was of the type OmpaLoompa, but TSC just annotates it as being any. If this wasn't an API that others will use, I probably would just deal with it, but I have to assume that others will use this Lib/API. So, at this point, if you have kept up with me, then my question should be pretty straight forward.

"How can I define the types for the properties on the custom WillyWonka extended array class?"

I am open to using another mechanism than Object.assign(...), so long as I can still access the OmpaLoompa typed properties as willyWonka[i:number]


Oh one other detail, I want the classes to be inferred to the imported class, in-other-words;

Do you see the comment that says, "/* DOCUMENT #1 */", and the other that says, "/* DOCUMENT #2 */"? I can't be coerced into typing the array's properties in document #2, because document two is an example of the Lib/API being used, the only part I will write is document #1. I need the types already defined when any arbitrary developer writes document #2 using the WillyWonk API.



I am pr

CodePudding user response:

Simple fix: just add OmpaLoompa to the generic parameter of Array.

class WillyWonka extends Array<OmpaLoompa> { /* ... */ }

Otherwise TypeScript will assume that the elements of Array are of type any.

  • Related