-2

I am using a recursive function and currently declared my_json as an array of strings and then when run recursively as a type 'any', but obviously that's not a perfect solution. my_json has a specific type, but when the function is run recursively it changes its type to a index key. How can I fix this? Any advice appreciated.

const findSomething = (my_json: any, value: string): boolean => {
    let exist = false;
    Object.keys(my_json).some(key => {
        exist =
            typeof my_json[key] === 'object'
                ? findSomething(my_json[key], value)
                : my_json[key] === value;
        return exist;
    });
    return exist;
};
findSomething(my_json, '123')
my_json: 
{
"aaa": [
"123",
"456",
"789"
],
"bbb": [
"000",
"001",
"002"
],
}
Vonder
  • 4,033
  • 15
  • 44
  • 61
  • 2
    https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types – Quentin Jul 05 '21 at 19:06
  • How `my_json[key]` could be of type `object` if you pass an array of strings? – Guerric P Jul 05 '21 at 19:22
  • Note, `my_json` [is *not* JSON](http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/) but an object. [What is the difference between JSON and Object Literal Notation?](https://stackoverflow.com/q/2904131) – VLAZ Jul 05 '21 at 19:30
  • What is the data you actually expect for `findSomething`'s initial call? Only an array? Or any kind of object? – VLAZ Jul 05 '21 at 19:37
  • @Vonder, your example code doesn't make sense as others have pointed out. What exactly is the type that you are passing in initially (i.e. not in successive recursive calls)? Is it an Array or not? That isn't JSON by any stretch. Are the strings supposed to be JSON? If so, your function is wrong; missing a call to `JSON.parse`. My answer ignored the details and attempted to answer the question in the title. Voting to close this until the question is properly formed. – Inigo Jul 05 '21 at 19:38
  • @Inigo, I am trying to check the existance of value in the following: { "aaa": [ "123", "456", "789" ], "bbb": [ "000", "001", "002" ], } i.e it would return true for 001 but false for 999 – Vonder Jul 05 '21 at 19:42
  • So, it's an object, where each value is an array of strings? Or is there going to be further nesting? – VLAZ Jul 05 '21 at 19:46
  • yes, thats right, there might be because it should work recursively with nested objects @VLAZ – Vonder Jul 05 '21 at 19:47
  • Per SO rules, you need to supply a full working example. You need to provide a call of the function with a good sample input that reflects the type you will pass in. And the function needs to actually work. The one you supplied DOESN'T MAKE SENSE, meaning you've never even run it? Please fix this before asking for help. – Inigo Jul 05 '21 at 19:51
  • @Inigo, yes - that was a typo I added after I edited, it should be : any and the whole question is about avoiding using :any in a recursive function. my bad. – Vonder Jul 05 '21 at 19:52
  • tag me when you've provided a complete working example with input. i.e. an input that is of the specific type you want besides `any`. – Inigo Jul 05 '21 at 19:53
  • So, is `{a: {b: ["x", "y", "z"]}}` valid (object nested in an object)? What about `{a: [{b: ["x", "y"]}, {c: ["z"]}]}` (array of objects nested in an object)? Are both valid or only one of them? – VLAZ Jul 05 '21 at 19:55
  • @Inigo - so the above works as it should with a type: any, but wanted to avoid it, the whole point is that type changes as its run recursively. – Vonder Jul 05 '21 at 20:00
  • You're not making any sense. "the whole point is that type changes as its run recursively". What does that mean? Provide examples, as I keep asking. At this point you should get that all these people don't understand what you want, and you are wasting everyone's time. And as I pointed out in reply to your comment on my answer, why do you expect your function signature can do better than `JSON.parse` and `JSON.stringify`? Please be respectful of people's time. You should be putting in more work than us. – Inigo Jul 05 '21 at 20:05
  • Your sample input doesn't even exercise the `typeof my_json[key] === 'object'` in your code. So obviously your input is NOT representative, or your code makes no sense. – Inigo Jul 05 '21 at 20:07
  • @Inigo thanks anyway, got an answer below. – Vonder Jul 05 '21 at 20:16
  • So since you made us all spend a lot of time on this, please explain what the answer was and what the question was. Out of respect please. – Inigo Jul 05 '21 at 20:20

2 Answers2

1

when the function is run recursively it changes its type to a index key

Yes, when you call findSomething(my_json[key], value), you are calling it with the index key value.


What you are calling my_json is an array. This naming confused me. I would expect something with that name to be a complex object or unknown type, not known to be an array.


Your problem is that you have your types mixed up. You cannot recurse into an array of strings, it's only "one level deep" because strings will not have iterable properties like an array or object.

You recurse into arrays or objects. First, clarify your understanding of the problem, then you will be able to fix the types.


If you are using Object.keys, you seem to be expecting an object. But you specified an array.

Assuming that recursion is relevant to your problem and your my_json object is not an array as you typed it, here's an attempt at refactoring.

type Haystack: {
  [key: string]: string | Haystack
}

function find(needle: string, haystack: Haystack): boolean {
  if (typeof haystack === 'string') return needle === haystack
  return Object.keys(haystack).some(key => find(needle, haystack[key]))
}

I hope you find it instructive. Good luck in your continuing education.

Patrick Fisher
  • 7,926
  • 5
  • 35
  • 28
  • yes, there was a mistake when I edited a question, its not an array of strings obviously, I've edited the question. You answered what I struggled to articulate :) Thank you. – Vonder Jul 05 '21 at 20:03
0

I'm going to ignore that your function implementation doesn't make sense given what you've described as the input so far, but I will try to address the title of your question.

These are the Typescript function signature of JSON.parse and JSON.stringify, as written by the creators of Typescript:

parse(text: string, reviver?: (this: any, key: string, value: any) => any): any;

stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;

Notice that any is all over the place as input arg and return type. That is the nature of a function that accepts arbitrary object input, which your function seems to expect to do as it recurses down the input when it checks typeof my_json[key] === 'object'?.

You can't do better than the Typescript creators.

Inigo
  • 12,186
  • 5
  • 41
  • 70
  • the whole point is that I dont want to use : any as a type – Vonder Jul 05 '21 at 19:27
  • It has to be `any`, because that is the type of arbitrary json. Look at the type def for `JSON.parse` and `JSON.stringify`. You can't do better than the makers of Typescript! – Inigo Jul 05 '21 at 19:33