Hacker News new | ask | show | jobs
by Stoids 2710 days ago
To add onto this, using lodash + TS is not the most pleasant experience. A lot of that has to due with current limitations of the type system (mostly variadic types [0]), but I find myself having to provide lots of generics rather than relying on inference. The overloads are not great.

I say this all with recognition that lodash greatly predates TS, and the maintainers have done an absolutely wonderful job in keeping up with the overall ecosystem (ESM, typings files, etc). I can't even begin to comprehend the amount of work that has gone in to keeping lodash so modern.

That being said, I wish the interaction was slightly better, since a lot of people just immediately bring in Lodash to any JS project.

[0] https://github.com/Microsoft/TypeScript/issues/5453

2 comments

I have the same experience; I wonder if anyone is working on a TS-friendly utility library, or if our best hope is the work on TS itself on [0]?
I wonder if ramda is any better in that regard?
I love Ramda and use it everywhere but sadly, it's somewhat lacking when it comes to type definitions. Everything in Ramda is curried and the types just don't reflect that very well so you get quite a few incorrect compiler errors.
Yeah, I remember liking the auto-currying, that makes sense it has a downside here.
Shouldn't tuples in rest parameters from TypeScript 3.0 [0] fix that?

[0] https://www.typescriptlang.org/docs/handbook/release-notes/t...

Not entirely.

For example, a function which takes a property path (in the form of an array of strings) and an object as parameters and returns the value at that path inside the object still needs overloads for every single tuple length.

  type Key = string | number | symbol;
  
  function get<T, K extends keyof T>(path: [K], obj: T): T[K];
  function get<T, K1 extends keyof T, K2 extends keyof T[K1]>(path: [K1, K2], obj: T): T[K1][K2];
  function get<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(path: [K1, K2, K3], obj: T): T[K1][K2][K3];
  function get<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2], K4 extends keyof T[K1][K2][K3]>(path: [K1, K2, K3, K4], obj: T): T[K1][K2][K3][K4];
  function get(path: Key[], obj: any) {
      if (path.length === 0) {
          return obj;
      }
      const key = path[0] as Key;
      const rest = path.slice(1) as [Key];
      return get(rest, obj[key]);
  }
  
  
  interface Foo {
      foo: {
          bar: {
              baz: {
                  val: number;
              }
          }
      }
  }
  
  declare const foo: Foo;
  const num = get(["foo", "bar", "baz", "val"], foo);
In this case, num is implicitly typed as number, but if the path would be longer, you'd need to add more overloads.