1

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 iterate 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

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: {
    },
  };

  // iterate 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

1
  • I added these two attributes to the array and the error is gone, but I don't want these in the array item structure, why do I need them? Commented Jan 28, 2022 at 7:38

1 Answer 1

1

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[], // <<============
          // ...
};
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much. I am new to typescript so this is somewhat confusing.
@EthanRichardson - (I've updated the answer a bit.) FWIW, I suggest not just trying to pick it up as you go along. Take a couple of hours to go through a decent introductory course, it'll save you time in the long run. :-) Happy coding!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.