3

I am having trouble writing a type that applies one type to all the bottom level props of another type.

The purpose of this is to use create a type which can convert all bottom level props to Ref<T> for Vue 3.

// Start with some type T
type T = ...

// And a 'function' to apply, U
type U<T> = ...

// This needs to apply U to all bottom level properties of T
// ('bottom level' are all props who's type does not extend object)
type DeepApply<T,U> = ???

Example:

{
  a: string,
  b: number,
  c: {
    c1: number,
    c2: string
  }
}

Would become

{
  a: Ref<string>,
  b: Ref<number>,
  c: {
    c1: Ref<number>,
    c2: Ref<string>
  }
}

Here's my best shot but TS throws an error both when trying to give a generic its own generic arguments (U<T[P]>) and when trying to pass a type with generics as a generic without explicitly defining its generics (DeepApply<T, Ref>).

type DeepApply<T, U> = {
  [P in keyof T]: T[P] extends object ? DeepUnion<T[P], U> : U<T[P]>;
};

type MyRefType = DeepApply<MyType, Ref>
Ben Wright
  • 33
  • 4
  • 2
    How about leaving `U` away and using the type `type DeepApply = { [P in keyof T]: T[P] extends object ? DeepApply : Ref }` – ssc-hrep3 Jan 27 '22 at 22:29
  • 1
    It's not directly possible to do this, sorry; there are some workarounds but nothing very nice. See [this question](https://stackoverflow.com/q/60007436/2887218) and its answers. – jcalz Jan 28 '22 at 01:34
  • Looks as if this is not likely to become a feature any time soon. Its a shame, this could open a lot of interesting doors in the typing system and eliminate a fair bit of repetition. – Ben Wright Jan 28 '22 at 13:54

1 Answers1

2

When a type is referenced, all it's generic parameters must be satisfied. Put another way, you can't pass a parameterized type without parameters to have it's parameters filled in later. There's just no syntax for that.

However, you can do it if you hardcode the Ref type. For example:

type DeepApplyRef<T> = {
  [P in keyof T]: T[P] extends object ? DeepApplyRef<T[P]> : Ref<T[P]>;
};

I don't think a solution exists that is quite as dynamic as you want here, if your recursive type knows the type that it's wrapping things up with, then this does work just fine.

Playground

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • That's too bad, I'd love to see an analog to higher order functions in the TS typing system. Thank you for your suggestion though, hardcoding Ref will get the job done. – Ben Wright Jan 28 '22 at 13:51