-
Notifications
You must be signed in to change notification settings - Fork 13k
Closed
Labels
Needs InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
Milestone
Description
Bug Report
In the following example, wrongInference.properties.account
inferred as unknown
. I was hoping it would be inferred the same way as wellInferred
.
// partialInferred.properties.name inferred as string, no other property as expected
const partialInferred = pickFromSchema(accountSchema, 'name')
// wellInfered.properties.account is well inferred
const wellInferred = propertiesToObjectSchema({ account: partialInferred })
// wellInferredAlternative.properties.account is well inferred
const wellInferredAlternative = {
type: 'object',
required: ['name'],
additionalProperties: false,
properties: pickFromSchema(accountSchema, 'name')
} as const
// wrongInferrence.properties.account inferred as `unknown`
const wrongInferrence = propertiesToObjectSchema({ account: pickFromSchema(accountSchema, 'name') })
I suppose this is a built-in mecanism to prevent too many recursions in typescript compiler.
🔎 Search Terms
- "typescript type propagation in nested function calls"
- "typescript max type recursion"
- "typescript wrongly inferred as unknown"
🕗 Version & Regression Information
I tried various versions in the playground UI, without finding one valid.
I am currently using version 4.9.4.
⏯ Playground Link
Full example available on playground.
💻 Code
interface BaseObjectSchema<Properties extends Record<string, unknown>> {
type: 'object'
properties: Properties
additionalProperties?: boolean
required?: ReadonlyArray<keyof Properties> | Array<keyof Properties>
}
/**
* Returns a new schema that picks some of the properties of base schema.
* Those properties are marked as required in the resulting schema.
*/
function pickFromSchema<
Properties extends Record<string, unknown>,
SubsetPropertyName extends keyof Properties & string,
Return = Required<
BaseObjectSchema<{
[PropertyName in SubsetPropertyName]: PropertyName extends keyof Properties ? Properties[PropertyName] : never
}>
>
>(schema: BaseObjectSchema<Properties>, ...properties: SubsetPropertyName[]) {
const newSchema = {
type: 'object' as const,
properties: {} as Record<string, unknown>,
additionalProperties: false,
required: properties
}
for (const property of properties) newSchema.properties[property] = schema.properties[property]
return newSchema as Return
}
/**
* Builds a new schema from a literal object, those keys are JSON schemas.
* Some properties can be set as optional using opts.optional.
*/
function propertiesToObjectSchema<Properties extends Record<string, unknown>>(
properties: Properties,
opts: { optional?: (keyof Properties)[] } = {}
): Required<BaseObjectSchema<Properties>> {
return {
type: 'object' as const,
properties,
required: (Object.keys(properties) as (keyof Properties)[]).filter(key => !opts.optional?.includes(key)),
additionalProperties: false
}
}
const accountSchema = propertiesToObjectSchema({
id: { type: 'string' },
name: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
updatedAt: { type: 'string', format: 'date-time' }
} as const)
// partialInferred.properties.name infered as string, no other property as expected
const partialInferred = pickFromSchema(accountSchema, 'name')
// wellInfered.properties.account is well infered
const wellInferred = propertiesToObjectSchema({ account: partialInferred })
// wellInferredAlternative.properties.account is well infered
const wellInferredAlternative = {
type: 'object',
required: ['name'],
additionalProperties: false,
properties: pickFromSchema(accountSchema, 'name')
} as const
// wrongInferrence.properties.account infered as `unknown`
const wrongInferrence = propertiesToObjectSchema({ account: pickFromSchema(accountSchema, 'name') })
🙁 Actual behavior
wrongInferrence.properties.account inferred as unknown
🙂 Expected behavior
Expecting wrongInferrence
to have the same type as wellInferred
and wellInferredAlternative
,
Metadata
Metadata
Assignees
Labels
Needs InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.