-
Notifications
You must be signed in to change notification settings - Fork 58
Description
Let's say, we have conditional args. We have an object, a key for that object, and maybe a value for when the given key does not exist in the object. Can be typed as:
type TestArgs<DATA extends Record<string, unknown>, NAME extends string> = {
name: NAME;
} & (NAME extends keyof DATA ? Record<never, never> : { value?: unknown });Such a type can actually provided by a third party library (which is my case. I also happen to be that author).
Now, let's have them on a component:
interface TestSignature<DATA extends Record<string, unknown>, NAME extends string> {
Args: TestArgs<DATA, NAME>;
}
class TestComponent<DATA extends Record<string, unknown>, NAME extends string> extends Component<
TestSignature<DATA, NAME>
> {
/// lalala
}so far all good. In a real-world scenario there might be more args, additional to that from that library, but important to your component. You curry them, also all cool. Now you wanna make the types so they are bound to that:
type BoundTest<DATA extends Record<string, unknown>, NAME extends string = string> = WithBoundArgs<
ComponentLike<{ Args: Omit<TestArgs<DATA, NAME>, 'value'> }>,
'name'
//^? Type 'string' does not satisfy the constraint
>;Well, that fails on a quite cryptic error:
Type 'string' does not satisfy the constraint '[...positional: Constrain<Get<Omit<TestArgs<DATA, NAME>, "value"> extends { Named?: object | undefined; Positional?: unknown[] | undefined; } ? { Named: Get<Omit<TestArgs<DATA, NAME>, "value">, "Named", {}>; Positional: Get<...>; } : { ...; }, "Positional", unknown>, unknown[], []>, ...named: MaybeNamed<...>] extend...'.It took me an afternoon tracing this one. Inside of WithBoundArgs the args are being determined, and I guess, this is the line:
| export type UnwrapNamedArgs<T> = T extends NamedArgs<infer U> ? U : T; |
called from here:
glint/packages/template/-private/index.d.ts
Line 137 in bd76fd7
| ...named: MaybeNamed<PrebindArgs<UnwrapNamedArgs<NonNullable<N>>, BoundArgs>>, |
My assumption here is that T extends NamedArgs<infer U> ? U : T isn't capable of understanding the conditional args and fails with whatever error hits first. The error message sure gets cryptic as it includes all glimmers "internal" type mappings.
Semi sort of workaround is to use ComponentLike and a lot of boiler plate code to replicate this behavior. However, it is not cascading if you want to make a bound component from a bound component, then the boilerplate becomes exponential.