TypeScript: Incorrect inference when using an optional argument

πŸ”Ž 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 5.3.3.

⏯ Playground Link

Link

πŸ’» Code

This is a followup on https://github.com/microsoft/TypeScript/issues/49951 which @Andarist asked me to open a follow-up issue. Also relates to https://github.com/microsoft/TypeScript/issues/47599

Probably better to check the playground for code examples, but here’s the TL;DR:

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 difference is in whether we have the argument for the step function or not. Note that if I do Parameters<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 }
  },
}))

πŸ™ 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.

Additional information about the issue

Like mentioned above, this is a followup on https://github.com/microsoft/TypeScript/issues/49951 and https://github.com/microsoft/TypeScript/issues/47599

About this issue

  • Original URL
  • State: closed
  • Created 6 months ago
  • Comments: 17 (8 by maintainers)

Most upvoted comments

It has been marked as a duplicate of that umbrella issue - and many issues were linked to it as its duplicates. I think this one was nice since it focused on a more specific problem. I still think this one is fixable (I fixed it locally without breaking any test cases). It was a busy weekend for me though and I’m investigating a better fix than what I have so far. I’ll report back when I’m done but it might take some days. TLDR: I still plan to open a PR fixing this πŸ˜‰

The schema defined in my example is not the same schema defined for the store.

Ah, ok - then the snipper in https://github.com/microsoft/TypeScript/issues/57021#issuecomment-1888949418 doesn’t exactly show the real usage. Thanks for the explanation.

If those are two different schemas then ye, it might work.

I have some idea how this might get fixed. Stay tuned πŸ˜‰ I wonder though - what’s anything in your real code? Is it really meant to always be unknown?