bar
is implicitly assigned an any
type, but that was your intention, right? You set up defc
to anticipate a parameter of type
T extends Record<string, any>
.
By providing the inner function signature as function({ bar })
to defc
, TypeScript deduces that the type of { bar }
extends Record<string, any>
, hence inferring that bar
is of type any
. This eliminates any implicit type errors.
Even if you modify Record<string, any>
to Record<string, number>
, TypeScript will still determine the type of bar
as number
and not raise objections.
However, TypeScript would alert you when attempting to use the newly created foo
with a non-number type:
function defc<T extends Record<string, number>>(f: (a: T) => void) {
return function(a: T) {
return f(a)
}
}
const foo = defc(function({ bar }) { // no issues here, TS can infer that `bar` is `number`
console.log(bar)
})
foo({ bar: 1 }) // ok!
foo({ bar: "wrong type" }) // Type 'string' is not assignable to type 'number'.
P.S. A potential bug could exist in your code. The behavior may be intentional or accidental.
When you don't specify the parameter type of the inner function passed to defc
, it allows unrestricted arguments for the resulting foo
function.
function defc<T extends Record<string, any>>(f: (a: T) => void) {
return function(a: T) {
return f(a)
}
}
const foo = defc(function({ bar }) {
console.log(bar)
})
foo({ bar: 1 }) // this is valid, will print "1"
foo({ notExists: "hm" }) // but this is also valid and will print "undefined"
foo
anticipates a Record<string, any>
and retrieves bar
from it; however, TypeScript won't raise warnings if bar
is missing inside that Record.
If you know the expected keys in advance, it's advisable to define them explicitly.
function defc<T extends Record<string, any>>(f: (a: T) => void) {
return function(a: T) {
return f(a)
}
}
const foo = defc(function <T extends Record<"bar", any>>({ bar }: T) {
console.log(bar)
})
foo({ bar: 1 }) // prints "1"
foo({ notExists: "hm" }) // invalid, `foo` expects only the `bar` key