Description
Bug Report
I'm running into very weird behavior when using identity functions. I'm writing a wizard system with schema (attached is a playground link with a very simplified version), and using constrained identity function to get inference.
The problem occurs in an argument of one property which is a function, when either of these occur:
- When the returned value from the identity function is using the
return
keyword (rather than a single-line return wrapped with parentheses).
OR - When declaring an optional argument in the identity function. The argument is declared in the type definition of the identity function, and when using
Parameters<typeof myFunction>
it's inferred correctly both when declaring the argument and when I not.
Both these issues are super weird to me, which means I'm either missing something very fundamental or I have found 2 rare bugs.
🔎 Search Terms
Inference, Return, Arguments, Parentheses, Identity Function.
🕗 Version & Regression Information
This reproduces in all available playground versions (tried down to 3.3.3), and also in 4.8.
⏯ Playground Link
Playground link with relevant code
💻 Code
Probably better to check the playground for code examples, but there:
TYPES DECLERATIONS:
type Schema = Record<string, unknown> // modified from original for the sake of the example, if it doesn't make sense
type StepFunction<
TSchema extends Schema = Schema,
> = (anything: unknown) => {
readonly schema: TSchema
readonly toAnswers?: (keys: keyof TSchema) => unknown
}
function step<TSchema extends Schema = Schema>(
stepVal: StepFunction<TSchema>,
): StepFunction<TSchema> {
return stepVal
}
EXAMPLES:
Notice the returned object of all functions is the same! The differences are in:
- whether we use the
return
keyword or not (?!?!) - whether we have the argument for the
step
function or not. Note that if I doParameters<typeof myStepValue>
even when the argument is missing, it's inferred correctly (!)
// WORKS: `keys` is inferred based on the `schema`
// - no argument for `step` function
// - no `return` keyword
const workingExample = step(() => ({
schema: {
attribute: 'anything',
},
toAnswers: keys => {
// RESULT: `keys` inferred successfully as `attribute`
type Test = string extends typeof keys ? never : 'true'
const test: Test = 'true'
return { test }
},
}))
// FAILS: `keys` is not inferred based on the `schema`
// - has argument for `step` function
const nonWorkingA = step(_something => ({
schema: {
attribute: 'anything',
},
toAnswers: keys => {
// RESULT: `keys` failed to be inferred hence defaults to `string`
type Test = string extends typeof keys ? never : 'true'
const test: Test = 'true'
return { test }
},
}))
// FAILS: `keys` is not inferred based on the `schema`
// - has `return` keyword rather than a "single-return" return with parentheses
const nonWorkingB = step(() => {
return {
schema: {
attribute: 'anything',
},
toAnswers: keys => {
// RESULT: `keys` failed to be inferred hence defaults to `string`
type Test = string extends typeof keys ? never : 'true'
const test: Test = 'true'
return { test }
},
}
})
🙁 Actual behavior
Nested value's function argument cannot be inferred correctly.
If I change the property (toAnswers
) from a function to a simple property, there are no inference issues.
🙂 Expected behavior
Nested value function argument should be inferred correctly regardless of the return
keyword or declaring the arguments.