π Search Terms
- destructured function parameters.
- contextual typing (?).
Not sure if I have the correct vocabulary.
Related issues :
β
Viability Checklist
β Suggestion
When inferring the type of a ({arg1, arg2}) => void callback, missing properties should be excluded from the inferred type.
Currently, TS infers it as ({arg1, arg2}: T) => void, with T being the constraint used during the inference.
I'd like the inferred type to be : ({arg1, arg2}: Pick<T, "arg1"|"arg2">) => void.
TS is able to properly infer the callback type when the whole argument is missing (i.e. () => void), so I guess my suggestion should also be technically possible ?
π Motivating Example
This can be useful to declare callbacks that must be compatible with a given context, while enabling their usage in other contexts, compatibles with the callbacks, not necessary with the original context.
Playground Link
type Bindings<CTX extends Record<string, any>> = {
[K in keyof CTX]: (ctx: CTX) => void; // <- in reality the type here is a little more complex.
}
// in reality we use B & Record<Exclude<keyof B, keyof T>, never> to exclude extra-keys.
function foo<T extends Record<string, any>, B extends Bindings<NoInfer<T>>>(p: {props: T, bindings: B}) {
return p;
}
const x = foo({
props: {
foo: 34, faa: "ok", fuu: "ok", fii: 42
},
bindings: {
fii:() => {}, // OK: () => void
foo:(a) => {}, // OK: (a: T) => void
faa:(args: {foo:number}) => {}, // OK: ({foo: number}) => void
fuu: ({foo}) => {} // NOK: ({foo}: T) => void / we want ({foo: number}) => void
}
})
// we could reuse it like :
foo({
props: {
...x.props,
fii: string // override a property with a completely different type.
},
bindings: {
...x.bindings,
fii: () => {} // binding may need to be overridden too.
}
})
π» Use Cases
- What do you want to use this for?
Writing reusable callbacks.
- What shortcomings exist with current approaches?
- What workarounds are you using in the meantime?
We need to explicit the types when destructuring, e.g. faa: (args: {foo:number}) => {}).
A possible workaround could have been the following, however TS doesn't do a "per key" inference.
type Bindings<CTX extends Record<string, any>, KEYS extends Record<keyof CTX, keyof CTX>> = {
[K in keyof CTX]: (ctx: Pick<CTX, KEYS[K]>) => void; // <- in reality the type here is a little more complex.
}
An alternative solution would be to allow TS to be more lax with ({foo}: T) => void, e.g. allowing ({foo: ...}) calls, even if the argument doesn't respect the T constrainst.
π Search Terms
Not sure if I have the correct vocabulary.
Related issues :
β Viability Checklist
β Suggestion
When inferring the type of a
({arg1, arg2}) => voidcallback, missing properties should be excluded from the inferred type.Currently, TS infers it as
({arg1, arg2}: T) => void, withTbeing the constraint used during the inference.I'd like the inferred type to be :
({arg1, arg2}: Pick<T, "arg1"|"arg2">) => void.TS is able to properly infer the callback type when the whole argument is missing (i.e.
() => void), so I guess my suggestion should also be technically possible ?π Motivating Example
This can be useful to declare callbacks that must be compatible with a given context, while enabling their usage in other contexts, compatibles with the callbacks, not necessary with the original context.
Playground Link
π» Use Cases
Writing reusable callbacks.
We need to explicit the types when destructuring, e.g.
faa: (args: {foo:number}) => {}).A possible workaround could have been the following, however TS doesn't do a "per key" inference.
An alternative solution would be to allow TS to be more lax with
({foo}: T) => void, e.g. allowing({foo: ...})calls, even if the argument doesn't respect theTconstrainst.