arktypeio/arktype

Fix cyclic intersection inference

ssalbdivad opened this issue · 1 comments

With the addition of optional keys inferred from chained values, cyclic scoped intersections are inferred as never (these worked prior to 2.0.0-rc.5).

It's unclear if it's a limitation of TS. I expect types like this are relatively rare in practice, so I'm willing to sacrifice them for chainable optionals/defaults. However, if it's possible to have both, that would be ideal!

Here are the removed tests that started failing that should be reenabled if this is fixed:

it("cyclic intersection", () => {
  const types = scope({
    a: { b: "b&a" },
    b: { a: "a&b" },
  }).export();
  attest(types).type.toString.snap(`Module<{
	a: { b: { a: { b: cyclic; a: cyclic }; b: cyclic } }
	b: { a: { b: { a: cyclic; b: cyclic }; a: cyclic } }
}>`);
});

it("intersect cyclic reference", () => {
  const types = scope({
    arf: {
      b: "bork",
    },
    bork: {
      c: "arf&bork",
    },
  }).export();
  attest(types.arf.infer).type.toString.snap(
    "{ b: { c: { b: cyclic; c: cyclic } } }"
  );
  attest(types.bork.infer).type.toString.snap(
    "{ c: { b: cyclic; c: cyclic } }"
  );

  const expectedCyclicJson =
    types.arf.internal.firstReferenceOfKindOrThrow("alias").json;

  attest(types.arf.json).snap({
    domain: "object",
    required: [
      {
        key: "b",
        value: {
          domain: "object",
          required: [
            {
              key: "c",
              value: expectedCyclicJson,
            },
          ],
        },
      },
    ],
  });
  const a = {} as typeof types.arf.infer;
  const b = { c: {} } as typeof types.bork.infer;
  a.b = b;
  b.c.b = b;
  b.c.c = b.c;

  attest(types.arf.description).snap("{ b: { c: arf&bork } }");
  attest(types.bork.description).snap("{ c: arf&bork }");

  attest(types.arf(a)).equals(a);
  attest(types.arf({ b: { c: {} } }).toString())
    .snap(`b.c.b must be an object (was missing)
b.c.c must be an object (was missing)`);

  attest(types.bork.json).snap({
    domain: "object",
    required: [
      {
        key: "c",
        value: expectedCyclicJson,
      },
    ],
  });
});

Nevermind, I found another solution.