Repository navigation
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
returnkeyword (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
returnkeyword or not (?!?!) - whether we have the argument for the
stepfunction 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.
Activity
ShayDavidson commentedon Jul 20, 2022
Possible related issue for the argument case: #25092, however it was fixed in 4.7 and my issue still reproduces there.
RyanCavanaugh commentedon Jul 20, 2022
This is pretty subtle but it's indeed a consequence of #47599. When the object literal is directly in the function body expression position we can do some safer inferences that can't occur in the
returnversion.typescript-bot commentedon Jul 22, 2022
This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
ShayDavidson commentedon Jul 31, 2022
If someone ever encounters this issue, found a temp solution!
By wrapping the returned value with an identity function, both the edge cases are working, see in this playground
e.g.
Andarist commentedon Sep 22, 2022
Note that
nonWorkingBmight get fixed if #50903 lands butnoWorkingAstill errors thereAndarist commentedon Sep 23, 2022
I think that this
noWorkingAis worth a separate issue. It feels different (to me) than the other case. Ping me there and I can try to look for a fix.ShayDavidson commentedon Jan 11, 2024
Hey Mateusz Burzyński (@Andarist)! A year and a half later I've encountered
notWorkingAagain and now I cannot fix it with my temp solution described above.Would you like me to open a separate issue?
Andarist commentedon Jan 11, 2024
This likely falls into the #47599 bucket (just like Ryan mentioned above). So it might be hard to get this fixed (that umbrella ticket isn't trivial) but maybe some carveout can be figured out for your case here, I'm not sure. I might take a look at it sometime later - and a fresh issue would definitely help me to remember about this.
ShayDavidson commentedon Jan 11, 2024
Thank you Mateusz Burzyński (@Andarist) - here's the followup #57021