Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can not add an array item to an existing array at the start of the array

I am trying to add a new array item to the start of an existing array and get an error. I am trying to add a new array item to the array that is constructed on the fly. The example code below causes an error using the unshift operation.

The array that I want to insert to is lRtn.document.mainTemplate.item.items and I am using lodash to itterate over the parameter _pUrls and for each url I am creating a new array item and want to push the new array item to the existing array lRtn.document.mainTemplate.item.items leaving the existing array content in place.

The error is get is

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Argument of type '{ type: string; description: string; source: any; }' is not assignable to parameter of type '{ type: string; duration: number; contentType?: undefined; content?: undefined; } | { type: string; contentType: string; content: string; duration?: undefined; }'.
  Type '{ type: string; description: string; source: any; }' is missing the following properties from type '{ type: string; contentType: string; content: string; duration?: undefined; }': contentType, content

The code that I have tried is here below, any help or guidance would be much appreciated.

export async function createAPLADirectiveBookReviews(
  _pUrls: any,
  _pFollowOn: string,
) {

  const lDescription = 'review';

  const lRtn = {
    type: constants.APLA.directiveType,
    token: constants.APLA.token,
    document: {
      version: '0.91',
      type: 'APLA',
      description: 'This document demonstrates key components used to create audio responses.',
      mainTemplate: {
        parameters: ['payload'],
        item: {
          type: 'Sequencer',
          description: 'Play this audio back in sequence',
          items: [
            {
              type: 'Silence',
              duration: 1500,
            },
            {
              type: 'Speech',
              contentType: 'PlainText',
              content: _pFollowOn,
            },
          ],
        },
      },
    },
    datasources: {
    },
  };

  // itterate over the urls and add them to the list
  _.forEach(_pUrls, function (url) {

    let lArrayItem = { 'type': 'Audio', 'description': lDescription, 'source': url };

    lRtn.document.mainTemplate.item.items.unshift(lArrayItem);

    });

  return lRtn;
}

Playground link

>Solution :

TypeScript infers the type of the lRtn.document.mainTemplate.item.items array as an array of this union type (except I’ve put the properties in the same order in both of them; TypeScript doesn’t care about property order):

{
    type: string;
    duration: number;
    contentType?: undefined;
    content?: undefined;
} | {
    type: string;
    duration?: undefined;
    contentType: string;
    content: string;
}

That means all members must match one of those two object shapes. But the object you’re trying to put in the array doesn’t match, it has this shape:

{
    type: string;
    description: string;
    source: any;
}

That doesn’t have duration (which it would need to match the first type of the union) and also doesn’t have contentType or content (which it would need for the second type of the union). So you can’t put it in that array.

You need to either give an explicit type the items array that makes those properties options, or make your lArrayItem object fit the shape of one of those union types, so it fits into the array.

The best way to explicitly give a type to that items array would be to define a type for lRtn:

interface ItemType {
    type: string;
    duration?: number;
    contentType?: string;
    content?: string;
}
interface ReturnType {
    document: {
        version: string;
        type: string;
        description: string;
        mainTemplate: {
            parameters: string[];
            item: {
                type: string;
                description: string;
                items: ItemType[];
            };
        };
    },
    dataSources: {
        // ...
    }
};

(probably in smaller parts than that) and use const lRtn: ReturnType = ... to assign a type to the whole thing.

But you can also do it with an as expression on the array:

interface ItemType {
    type: string;
    duration?: number;
    contentType?: string;
    content?: string;
}
// ...
const lRtn = {
          // ...
          items: [
              {
                  type: 'Silence',
                  duration: 1500,
              },
              {
                  type: 'Speech',
                  contentType: 'PlainText',
                  content: _pFollowOn,
              },
          ] as ItemType[], // <<============
          // ...
};
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading