Problem
Home emits false TS2345 diagnostics when a method type parameter constrained to a class type parameter is passed to a built-in generic method whose parameter retains the class placeholder. A minimal strict repro uses a recursive generic interface:
interface State<Out = unknown> { output: Out }
type Standard<T> = { input: T; output: T };
interface SchemaType<Out = unknown, S extends State<Out> = State<Out>> {
state: S;
standard: Standard<this>;
}
class Registry<Schema extends SchemaType = SchemaType> {
private map: WeakMap<Schema, boolean> = new WeakMap();
add<S extends Schema>(schema: S) {
this.map.set(schema, true);
this.map.get(schema);
}
}TypeScript 6.0.3 and the TypeScript 7 native preview accept the source. Home reports one TS2345 at each call.
This surfaced after #662 gave WeakMap annotations their real key type; the pinned Zod graph has the same relationship in its registry.
Root cause
typeParameterConstraint returns a resolved placeholder target, while typeParameterConstraintAssignableToParamDepth compares that result against the method signature's potentially unresolved parameter placeholder. Recursive generic interface materialization makes those IDs differ even though they represent the same declared class type parameter, and the fallback structural relation rejects the recursive pair.
Fair oracle
Positive:
- class type parameter constrained by a recursive generic interface;
- method
S extends Schema; Spassed to bothWeakMap<Schema, V>#setand#get;- TypeScript 6.0.3 and TypeScript 7: 0 diagnostics;
- Home parent: 2 false
TS2345diagnostics.
Negative control:
- an unrelated primitive argument must remain
TS2345.
Acceptance criteria
- Compare resolved placeholder identities at the shared type-parameter constraint boundary.
- Do not use type-parameter names, Zod symbols, source locations, or permissive widening.
- Preserve rejection for unrelated arguments.
- Add permanent regression coverage.
- Verify the pinned Zod graph gains no candidate-only diagnostic identities.
Blocks the zero-addition admission gate for #662; tracks #416 and #548.