1

I wrote a Typescript function where my argument could be either a string's array or a raw object.

its prototype is:

export const myFunction = async (line: string[] | myCustomType, config: any): Promise<String> => {
  if (line?.length < 2)
    //line is a string[]
  else
    //line is a mysCustomType
}

Where myCustomType is a raw object with a lot of properties / method.

In JavaScript I would have just tried to access to line?.length and if it would have been undefined I would have treated line like an instance of myCustomType (because myCustomType doesn't have length properties.

an array being an object, I already created a method in the Object class allowing me to directly differences the two type:

declare global {
  interface Object {
    isCustom(): boolean;
  }
}

Object.prototype.isCustom = function () {
  return false;
};

Where the method isCustom already exist in type myCustomType and doesn't return false. So I can differencies line's type, but the typescript doesn't allow me to compile.

Property 'length' does not exist on type 'string[] | myCustomType'.
  Property 'length' does not exist on type 'myCustomType'

Shall I declare line's type to be of Object and use my isCustom() method ? or is it uggly ?

Any ideas to get rid of this problem ?

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
Paul-Marie
  • 874
  • 1
  • 6
  • 24
  • 1
    [If you want to differentiate between array and object](https://stackoverflow.com/questions/767486/how-do-you-check-if-a-variable-is-an-array-in-javascript), why not just use `Array.isArray(line)`? Why do you have to change the built-in prototype of all objects everywhere? – VLAZ Feb 13 '22 at 13:17
  • Because even with the `Array.isArray(line)`, Typescript wouldn't allow me to compile ! – Paul-Marie Feb 13 '22 at 13:18
  • please post more of your code then. – Matthieu Riegler Feb 13 '22 at 13:19
  • Seems to work fine for me:[Playground Link](https://www.typescriptlang.org/play?#code/JYOwLgpgTgZghgYwgAgLYE8DCBXAzmAe1QBV0AHFAbwFgAoZB5YXHfIgLmQAoBKZAXgB8yMFGwQA3HUbIYBAp3xRQAcym0AvnWkICIfGnQAxbCARhgegcji50Z7gBtQERaNUBtALrIAPodZCEnIIABpkXRAYYBVOOBB0Hk4ABSgiZggAHgBldxAVYSFkGnoZYBhuAEEoKDh0ADpmatr0LmcQCB4+EpleqAgwbCgQZHaIeoArAlAuACJw2Z4JZAB6FbgaupECZCVVaRkNZAhHXCoD3oZ+weHRl3q5AmW15AmJvDAbXbyVC4YtTRAA) – VLAZ Feb 13 '22 at 13:21
  • Wait `if (line?.length < 2)` doesn't mean what you claim. If the length is 1, then you'd go into the `else` and you'd expect *the string with one character* to be `myCustomType`. TS is very correctly warning you here, why do you not want to use proper logic instead? – VLAZ Feb 13 '22 at 13:24
  • It was just an example to show you the `.length` method who'll works fine in JS willn't compile in TS, so what is the proper logic in this situation ? that's my question ! – Paul-Marie Feb 13 '22 at 13:29
  • The proper logic, according to me, is to *not* pollute built-ins and to instead use a proper type guard. However, you say it "doesn't work" which I can't really believe. Nor can I really help, since you're now asking me to somehow give you a solution for code I do not know. – VLAZ Feb 13 '22 at 13:36

1 Answers1

0

The proper logic is

var isStringArray = false;
if (Array.isArray(line)) {
    isStringArray = true;
    line.forEach(function(item) {
        if (typeof item !== "string") {
            isStringArray = false;
        }
    });
}

Explanation: you need to check whether your variable is an array and then whether all its members are strings. Your way of checking for the value of length and validating based on that is incorrect even in principle, because your custom object may have a length member even if it's not an array. Also, in practice, your string array could have a length of 1 or 0 as well and it would be a string array even then.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175