Encountering strange behavior while working on identity functions in a wizard system schema. Using a constrained identity function for inference is causing issues with one property that cannot be inferred when using the following:
- When the return value from the identity function uses the
return
keyword instead of a single-line return wrapped with parentheses.
OR
- When declaring an optional argument within the identity function. The argument is declared in the type definition of the identity function, and when utilizing
, it's correctly inferred both with and without declaring the argument.Parameters<typeof myFunction>
These issues are quite puzzling, indicating a possible oversight on my part or the presence of two rare bugs.
This issue persists across all available playground versions (tested down to 3.3.3) and even in version 4.8.
Check out the relevant code on the playground
To better understand, here are some snapshots:
TYPES DECLARATIONS:
type Schema = Record<string, unknown> // altered from original example for illustration
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: Note that all functions return the same object! Variations lie in:
- Whether the
return
keyword is used or not (!?!) - If there is an argument for the
step
function or not. Even if I use
with a missing argument, it still infers correctly (!)Parameters<typeof myStepValue>
// WORKS: `keys` is correctly inferred based on the `schema`
// - no argument for `step` function
// - absence of `return` keyword
const workingExample = step(() => ({
schema: {
attribute: 'anything',
},
toAnswers: keys => {
// RESULT: `keys` successfully inferred 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`
// - includes an argument for `step` function
const nonWorkingA = step(_something => ({
schema: {
attribute: 'anything',
},
toAnswers: keys => {
// RESULT: `keys` fails to be inferred and 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`
// - uses `return` keyword instead of a "single-return" wrapped in parentheses
const nonWorkingB = step(() => {
return {
schema: {
attribute: 'anything',
},
toAnswers: keys => {
// RESULT: `keys` fails to be inferred and defaults to `string`
type Test = string extends typeof keys ? never : 'true'
const test: Test = 'true'
return { test }
},
}
})