by

Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • 10:20
    DanielRosenwasser labeled #39548
  • 10:20
    DanielRosenwasser labeled #39548
  • 10:20
    DanielRosenwasser opened #39548
  • 10:20
    DanielRosenwasser labeled #39548
  • 10:20
    DanielRosenwasser labeled #39548
  • 10:12
    ShuiRuTian review_requested #39389
  • 10:11
    DanielRosenwasser labeled #39546
  • 10:02
    mischnic opened #39547
  • 09:15
    keelii opened #39546
  • 09:09
    nzhl edited #39545
  • 09:07
    nzhl edited #39545
  • 08:55
    nzhl opened #39545
  • 08:46
    bitlab-code edited #39544
  • 08:41
    bitlab-code edited #39544
  • 08:39
    bitlab-code edited #39544
  • 08:38
    bitlab-code opened #39544
  • 08:28
    kitsoRik closed #39462
  • 08:01
    meteorlxy edited #39543
  • 07:57
    meteorlxy opened #39543
  • 07:33
    Gurran edited #39542
Keith Layne
@keithlayne
oh wait, missed the function part
this looks like it does what you want.
Keith Layne
@keithlayne
maybe this one is a little nicer.
Reko Tiira
@rekotiira
@keithlayne wow amazing, that is exactly what I want! The only hurdle is that I want the Foo to be parameterized for the MapArgs. I came up with a solution like this but is there a nicer way?
Can you also explain why that works :D
Keith Layne
@keithlayne
Just do this
Reko Tiira
@rekotiira
Oh I see, that's a neat trick
Keith Layne
@keithlayne
How it works:
  1. To infer a tuple, you gotta extend Foo[] & { 0: Foo }. From experimentation, you can't use any other type for the first element.
  1. Mapped types work over tuples, which is great, but they have to be "homomorphic" or it will get weird, i.e. { [K in keyof T]: whatever }
  1. You need the & keyof T to let TS know that you can index T with the type you get from your mapping. This has the handy side-effect of turning bad keys into never. However, the constraint on K in the function is enough to give you an error if you try to use the wrong key.
Big shout out to markdown for making my numbered lists more awesome.
@rekotiira does that answer your questions? Lemme know what I missed.
Keith Layne
@keithlayne
You could do another trick to make Wrapped<never> turn into never:
type Wrapped<T> = T extends unknown ? { value: T } : never;
janusqa
@janusqa
interface LoginFormStateType {
  account: { username: string; password: string };
  errors: { [key in LoginFormStateType['account']]?: string };
}
Hi all, how would I be able to do something like this
The error this gives is that
Type '{ username: string; password: string; }' is not assignable to type 'string | number | symbol'.
Keith Layne
@keithlayne
the never in the false condition could be literally any type. Distributed conditionals will short-circuit when you feed never as T, so it's impossilbe to take that branch :smirk_cat:
@janusqa you seem to be missing a keyof in your mapped type index
janusqa
@janusqa

@janusqa you seem to be missing a keyof in your mapped type index

Well well well you hit the nail on the head @keithlayne

thank you
Keith Layne
@keithlayne
@rekotiira there's a side-effect of that last type I showed though, Wrapped<1 | 2> is { value: 1 } | { value: 2 }, which is different that what you had before, and may not be what you want, but I think in practice would probably be okay.
@janusqa :thumbsup: no problem
All I have is a :hammer: , so everything looks like a nail
@fatcerberus just checking to make sure you're alive
Reko Tiira
@rekotiira
@keithlayne sorry for late reply, my Internet is having some issues. But yes, that answers my questions. Thanks a ton. :)
Now that I'm here, here's another interesting problem I was having the other day, not sure if there's any other way to do this, but let's ask anyway. I want to be able to do something like:
foo(obj, 'deep', 'nested', 'child'). I solved that by having a bunch of overloads for different nested levels, like:
const foo = <T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]>(obj: T, k1: K1, k2: K2, k3: K3)
Is there a way to do recursive look-ups like this without overloading?
Russell Anthony
@russell-dot-js

Howdy!!! I usually find a way to hack things in typescript and this is the first one I've really gotten stuck on. I'm assuming it's going to be a "doh" moment and I just don't know wha to search for.

Let's say you have a merchant who sells items. All possible items are known, so we represent those as an enum:

enum Items {
  Necklace = "Necklace",
  GolfBall = "GolfBall",
  Yarn = "Yarn",
}

Each merchant has a subset of items, and for each of those they have a price and a variant. But let's say you're adding types to an existing project, and need to define the types for something that looks like this:

const merchant = {
  prices: {
    [Items.Necklace]: 50,
  },
  variants: {
     [Items.Necklace]: "Gold",
  },
}

Basically, both prices and quantity could be typed as Record<Items, T>

But the keys of both prices and variant will always be the same. E.g. there will never be a "GolfBall" variant when there is no GolfBall price, and vice versa.

I've been trying to go down this rabbit hole, and I think I'm close, but no cigar:

type Merchant<T extends keyof Items> {
  prices: Record<typeof Items[T], number>;
  variants: Record<typeof Items[T], string>;
}

As well as:

type Merchant<T extends Items[]> {
  prices: {
     [key in T]: number;
  }
  variants: {
     [key in T]: string;
  }
}

To no avail. Please tell me why I'm an idiot and where I need to look to get this right :)

Russell Anthony
@russell-dot-js

Actually, this worked:

type Merchant<T extends Items> {
  prices: Record<T, number>;
  variants: Record<T, string>;
}

:D

could have sworn I tried that first but there you have it
Reko Tiira
@rekotiira

Is it possible to enforce TS to pick a certain overload depending on whether you're providing an anonymous function with no type information (= I want TS to do type inference), vs providing a function that already has type information (= I want to check some constraints on the function parameters).

Basically I only want to do type-inference if type information is missing, otherwise not.

Reko Tiira
@rekotiira

To provide a bit of contest, I have something like this:

interface ValidateFn<ErrorType> = {
  <Dependencies, FormData, ExternalData>(
    context: ModelContext<any>,
    dependencies: Dependencies,
    validatorFn: ValidatorFn<
      ExtractDependencies<Dependencies>,
      FormData,
      ExternalData,
      ErrorType
    >
  ): ValidateDefinition<ErrorType>;
};

I want TS to infer the ValidatorFn when you provide an anonymous function to it. However now if you provide a pre-typed function, I want to check that the first argument (the first generic type passed to ValidatorFn) is compatible with the Dependencies. Basically I need a "ExtractDependencies<Dependencies> extends arg 1 of ValidatorFn`, but not sure how to do that properly

Reko Tiira
@rekotiira
Or can I somehow access the actual inferred type? I.e. Whatever ValidatorFn<...> gets inferred as? That way I could add a Parameters<InferredType>[0] extends .. constraint
I tried to move the whole ValidatorFn as a generic type for the ValidateFn with a Validator extends ValidatorFn<...>, but then I lose type inference for anonymous functions

also tried reverting the logic, i.e. instead of using unboxed ExtractDependencies for ValidatorFn, I make sure that Dependencies extends a boxed type of the args:

  <
    ValidatorInput,
    Dependencies extends WithOptionalAnyModelContext<ValidatorInput>,
    FormData,
    ExternalData
  >(
    context: ModelContext<any>,
    dependencies: Dependencies,
    validatorFn: ValidatorFn<ValidatorInput, FormData, ExternalData, ErrorType>
  ): ValidateDefinition<ErrorType>;

With this the type constraint for pre-typed funcs works perfectly, but then the type inference does not work

Salathiel Genèse
@SalathielGenese
@rekotiira - This all sounds like an XY problem.
Ben Carp
@carpben
Hi all,
I'm getting a very strange Typescript bug
image.png
S can't be used to type Record<S, string>
Does anyone understand how this could be?
Raziel
@rraziel
Those colors make me think of the 80s
Kevin Pinto
@ShakurOo
Does anyone has already experiencing some issues according aliases path resolution with tsc build compilation in node js environment please ?
Raziel
@rraziel
The paths part of tsconfig?
Kevin Pinto
@ShakurOo
Yes
tsc -b doesn't convert aliases symlinked paths into relatives path (like babel does through babel-module-resolver).
My build is a standelone package wich need to be serve by another js application. This application, during the compilation time is not able to reading aliases path (node js environment).
image.png
image.png
Gerrit Birkeland
@Gerrit0
Yes, that's expected. TS doesn't do that.
darsain
@darsain

I don't know how to satisfy this generic type :(

function foo<T extends (string | number)>(value: T): T {
    if (typeof value === 'string') return '5';
    if (typeof value === 'number') return 5;
}

I'm getting error on both return statements: https://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=4&pc=2#code/GYVwdgxgLglg9mABMOcA8AVRBTAHlbMAEwGdEAKEqAJxjAHNEAfRMEAWwCNtqBKAPnIA3AIYAbENgBciDLxlYA3gChEaxDGAUoATwAO2OFtETsiALyXEAciq0G13omrYoIakmsBWawG5V6pra+obG4pIWVtZsXDyOzq7uSF7+AL5AA

matrixbot
@matrixbot
kaito2 ts function foo<T extends (string | number)>(value: T): T { if (typeof value === 'string') return '5' as T; return 5 as T; }
darsain
@darsain
oh so I have to cheat? can I not make TS understand that the code is correct? I guess that would require getting the generic type at runtime, which isn't possible
matrixbot
@matrixbot
kaito2 If you call it 'cheating' then yes? The thing is, you're equating the input type to the output type, but when you type-guard the input type, that's not the output type anymore. I guess you could just omit the output type?