0

I'm investing hours now, but don't want to give up :-)

I have an object, an target-path and a callback-function (with the "target-value" from the object)

This screenshot shows my wish

  • a value and
  • the correct type of this :-)

enter image description here

Do you have any Idea if this is possible?
I need the function param targetPath inside a type, see TARGET_PATH_AS_TYPE
Here is my current sourcecode:

type DotPrefix<T extends string> = T extends '' ? '' : `.${T}`
type DotNestedKeys<T> = T extends Date | any[]
  ? ''
  : (
      T extends object
        ? {
            [K in Exclude<keyof T, symbol>]: `${K}${DotPrefix<
              DotNestedKeys<T[K]>
            >}`
          }[Exclude<keyof T, symbol>]
        : ''
    ) extends infer D
  ? Extract<D, string>
  : never

type PropType<T, Path extends string> = string extends Path
  ? unknown
  : Path extends keyof T
  ? T[Path]
  : Path extends `${infer K}.${infer R}`
  ? K extends keyof T
    ? PropType<T[K], R>
    : unknown
  : unknown

type TestType = {
  a: {
    b: Date
    c: number
    d?: string
  }
}

const myObject: TestType = {
  a: {
    b: new Date(),
    c: 12
  }
}

type MagicFunctionProps<T> = {
  sourceObj: T
  targetPath: DotNestedKeys<T>
  render: (value: PropType<T, 'a.b' /* TARGET_PATH_AS_TYPE */>) => void
}

const magicFunction = <T>({
  sourceObj,
  targetPath,
  render
}: MagicFunctionProps<T>): void => {
  render(`${sourceObj}[${targetPath}] > logic comes later` as any)
}

magicFunction<TestType>({
  sourceObj: myObject,
  targetPath: 'a.b',
  render: (value) => {
    console.log(value)
  }
})

DotNestedKeys: https://stackoverflow.com/a/68404823/8270748
PropTypes: https://github.com/microsoft/TypeScript/pull/40336

Thanks!!

Greetings crazyx13th

crazyx13th
  • 533
  • 5
  • 10
  • These sorts of deep-path questions are interesting to me but there are always so many edge cases around optional properties, unions, index signatures, etc. Like, with `{a?: {b: string}`, what is the type at `"a.b"`? *Is* there even a type there? Maybe the `a` property doesn't exist so `"a.b"` might not be a valid path. I hate spending an hour on a type only to find out there's some super important edge case that requires a change to the whole approach. – jcalz Mar 30 '22 at 18:23
  • For example, [this approach](https://tsplay.dev/NrKJam) might possibly meet your needs but it's hard to tell since it's all edge cases all the way down. First, using `Date` is fairly obnoxious because you're going to get all the methods and properties of `Date` nested in there. How should it know where to stop? – jcalz Mar 30 '22 at 18:55
  • I wonder why you don't just make `magicFunction` generic in both the type and the path, like [this](https://tsplay.dev/N9y88N)? That's got to be easier than generating the full union of all possible paths. Let me know if either of these is what you want to see here. – jcalz Mar 30 '22 at 19:03
  • wow, awwsome... looks soo "easy" if I see your solution (but for me it wasn't), very clean clear code! thanks you!! – crazyx13th Mar 31 '22 at 05:40
  • next problem are optional fields, I tried "DeepRequire" but doesnt work see https://tsplay.dev/NBjA4N ( I changes `a:` to `a?:`) thanks! – crazyx13th Mar 31 '22 at 09:44
  • "next problem are optional fields" <-- this is exactly the sort of thing I need spelled out ahead of time so I don't spend time working on the wrong approach. Please give desired input/output requirements. What should we do if `a` is optional? If you do `myObject.a.b` and `myObject.a` isn't present then you will have a runtime error; arguably, rejecting `"a.b"` is correct. If you want to see something *else* happen then you need to give explicit rules for it. – jcalz Mar 31 '22 at 12:59
  • You say "I tried 'DeepRequire' but doesnt work". Unfortunately "it doesn't work" is enough information, see what constitutes a [mre] (specifically in there it says "it doesn't work" is insufficient to describe what's happening). If I define `DeepRequired` like [this](https://tsplay.dev/m35YEw) then it "works", although again, it's not clear to me why it's acceptable to pretend optional properties are actually required. – jcalz Mar 31 '22 at 13:04
  • I'm happy to write up a post with an answer but I need more information first. – jcalz Mar 31 '22 at 13:04
  • Sorry, I just look at the target objects. there are all automatic generated data for a rest api. means value could be string, number, boolean, string[], number[], boolean[] (sorry Date was only an example to check the type) – crazyx13th Mar 31 '22 at 15:28
  • I don't understand that at all, sorry. Could you try again? – jcalz Mar 31 '22 at 15:30
  • sorry... have accidentally sent the message in the middle of writing with the return key :-D .. you are too fast! :-) – crazyx13th Mar 31 '22 at 15:32
  • Okay, but I still don't understand. Are you saying we don't have to worry about `Date`? And if so, could you replace the example code with something more appropriate? I asked a bunch of stuff about what to do with optional properties, `DeepRequired`, etc, but I don't see that you've answered them. Is my solution above workable for you or not? If it is I can write up the answer explaining it, but I don't want to start and then find out there's a problem. – jcalz Mar 31 '22 at 15:36
  • Your last example with YOUR DeepRequired seems to work! ... my was `type DeepRequired = { [K in keyof T]: Required> }`, an yeah, the values are "simple"- ones (no Date, function,...). Sorry that I have not answered everything, today a bit hectic at work. Let me please still test your last example properly, I give you then still a hopefully final Feedback, thank you for your time!!!! – crazyx13th Mar 31 '22 at 16:01

0 Answers0