Repository navigation
Inconsistent compiler behavior with recursive conditional type as variables or parametersΒ #60221
Copy link
Copy link
Closed
Labels
QuestionAn issue which isn't directly actionable in codeAn issue which isn't directly actionable in code
Description
π Search Terms
recursive conditional type compilation variable parameter
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about recursive conditional types
β― Playground Link
π» Code
type StringConstraints = { required?: boolean }
type ObjectConstraints = { required?: boolean }
type StringSchema = ["string", StringConstraints]
type ObjectSchema<T extends object | null | undefined> = ["object", { [P in keyof T]: SchemaFor<T[P]> }]
type SchemaFor<T> =
[T] extends [string | null | undefined] ? StringSchema :
[T] extends [object | null | undefined] ? ObjectSchema<T> :
never
type AnySchema = StringSchema | ObjectSchema<{}>
type Person = {
name: string | null
}
function validate(schema: AnySchema) {
return []
}
const schema1 = ["object", {
name: ["string", { required: true }],
}]
const schema2: AnySchema = ["object", {
name: ["string", { required: true }],
}]
const schema3: SchemaFor<Person> = ["object", {
name: ["string", { required: true }],
}]
validate(schema1)
// Error: Argument of type '(string | { name: (string | { required: boolean; })[]; })[]' is not assignable to parameter of type 'AnySchema'.
// Type '(string | { name: (string | { required: boolean; })[]; })[]' is not assignable to type 'ObjectSchema<{}>'.
// Target requires 2 element(s) but source may have fewer.(2345)
validate(schema2) // No type checking, name and required can be mispelled
validate(schema3) // Works as expected, type checking is ok
validate(["object", { // Works partially, type checking works on "object" but not on "string" or "required"
name: ["string", { required: true }],
}])π Actual behavior
Type-checking only works with schema3, where all properties have to be correctly spelled. schema1 gives a compiler error (see code). schema2 can be completely misspelled with no errors. Passing directly a schema as parameter to the validate function works partially.
π Expected behavior
All four schema definitions should work with correct and complete type-checking.
Additional information about the issue
No response
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
QuestionAn issue which isn't directly actionable in codeAn issue which isn't directly actionable in code
Activity
jcalz commentedon Oct 14, 2024
I don't see a TypeScript bug anywhere in here. Your type
ObjectSchema<{}>is just["object", {}], and that's quite a wide type that accepts just about anything in the second element. You're not really using generics in a way that does much, for most of this code. TypeScript has no idea inschema1that you care about the literal types of the string literals in there. I don't see where in this code you have given TypeScript the information it would need to check things the way you want.If I were to try to write code like this, I'd make
validate()generic, make sure thatconstassertions didn't invalidate your types (so you should acceptreadonlytuples), and either write your object literals directly as arguments tovalidate(), or useconstassertions ahead of time, and never annotate to a type wider than you care about. Maybe something likePlayground link
Maybe I made different decisions from the ones you would make, but at no point here am I seeing something that looks like a bug in the language. You might want to close this issue and ask questions in Discord or Stack Overflow if you can't figure out how to adapt this to your use case.
RyanCavanaugh commentedon Oct 14, 2024
It seems like what you want is this
because the
TinObjectSchemaisn't really doing anything in a way that works.There are a lot of schema-like libraries doing stuff like this correctly, e.g.
zod, and I'd recommend reading their source to see how to do this.fwolff commentedon Oct 15, 2024
Thank you both for your quick replies.
Joe Calzaretta (@jcalz) your ValidateSchema was the key.
Ryan Cavanaugh (@RyanCavanaugh) I will check the zod library.
Closing the issue.