Repository: vazco/uniforms (ts)

Issue:
Unsupported field type: undefined
Hi, we are getting an error "Unsupported field type: undefined" when using the json schema below.
If we change the reference in `my_property` to `GoodType` then the form is rendered without errors. It seems to be a problem with `BadType` being a `$ref`... thanks

react@17.0.2
uniforms-bridge-json-schema@3.5.5
unforms-material@3.5.5
uniforms@3.5.5

```
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$ref": "#/definitions/MyObjectType",
  "definitions": {
    "MyObjectType": {
      "type": "object",
      "properties": {
        "my_property": {
          "$ref": "#/definitions/BadType"
        }
      },
      "required": ["my_property"],
      "additionalProperties": false
    },
    "BadType": {
      "$ref": "#/definitions/GoodType"
    },
    "GoodType": {
      "type": "integer"
    }
  }
}
```

Pull request:
Implemented recursive `$ref` resolution (fixes #1006).
This PR adds recursive `$ref` resolution in JSON Schema Bridge. Previously, only the first `$ref` was resolved so `$ref` pointing to another `$ref` caused errors. Also added tests for this case.

Patch:
diff --git a/docs/examples-custom-fields.mdx b/docs/examples-custom-fields.mdx
index b165b49e..7bcbd0a6 100644
--- a/docs/examples-custom-fields.mdx
+++ b/docs/examples-custom-fields.mdx
@@ -21,7 +21,7 @@ field props here, like value or onChange for some extra logic.
 
 ### `CustomAutoField`
 
-These are two _standard_ options to define a custom `AutoField`: either using `connectField` or simply taking the code from the [original one](https://github.com/vazco/uniforms/blob/master/packages/uniforms-unstyled/src/AutoField.js#L14-L47) _(theme doesn't matter)_ and simply apply own components and/or rules to render components. Below an example with `connectField`.
+These are two _standard_ options to define a custom `AutoField`: either using `connectField` or simply taking the code from the [original one](https://github.com/vazco/uniforms/blob/master/packages/uniforms-unstyled/src/AutoField.tsx#L14-L47) _(theme doesn't matter)_ and simply apply own components and/or rules to render components. Below an example with `connectField`.
 
 ```tsx
 // Remember to choose a correct theme package
diff --git a/docs/faq.md b/docs/faq.md
index 9a9f71e6..688540f4 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -245,3 +245,21 @@ const ChangedForm = ({ model }) => (
   </AutoForm>
 );
 ```
+
+### Why am I suddenly getting type errors in my form components?
+
+After introduction of TypeScript in `uniforms@3.0.0`, in the initial versions all form components in theme packages were typed as `any`.
+Natural strict typing is not possible due to TypeScript constraints. In one of the versions we have decided to change this approach and explicitly cast all of the form types.
+If you experience any errors regarding form types, please [file us a bug report](https://github.com/vazco/uniforms/issues/new?assignees=&labels=&template=bug-report.md) and use one of the following workarounds for the time being in your project.
+
+```tsx
+const AnyAutoForm: any = AutoForm;
+<AnyAutoForm untypedProp={1} />;
+
+// or
+
+const anyProps: any = {
+  untypedProp: 1
+}
+<AutoForm {...anyProps} />
+```
diff --git a/packages/uniforms-antd/src/AutoForm.tsx b/packages/uniforms-antd/src/AutoForm.tsx
index a8f25da9..dd83b25b 100644
--- a/packages/uniforms-antd/src/AutoForm.tsx
+++ b/packages/uniforms-antd/src/AutoForm.tsx
@@ -2,12 +2,12 @@ import { AutoForm } from 'uniforms';
 
 import ValidatedQuickForm from './ValidatedQuickForm';
 
-function Auto(parent: any): any {
+function Auto(parent: any) {
   class _ extends AutoForm.Auto(parent) {
     static Auto = Auto;
   }
 
-  return _;
+  return (_ as unknown) as AutoForm;
 }
 
 export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-antd/src/BaseForm.tsx b/packages/uniforms-antd/src/BaseForm.tsx
index 798ed59a..6ba42984 100644
--- a/packages/uniforms-antd/src/BaseForm.tsx
+++ b/packages/uniforms-antd/src/BaseForm.tsx
@@ -1,7 +1,7 @@
 import classnames from 'classnames';
 import { BaseForm } from 'uniforms';
 
-function AntD(parent: any): any {
+function AntD(parent: any) {
   class _ extends parent {
     static AntD = AntD;
 
@@ -21,7 +21,7 @@ function AntD(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as typeof BaseForm;
 }
 
 export default AntD(BaseForm);
diff --git a/packages/uniforms-antd/src/QuickForm.tsx b/packages/uniforms-antd/src/QuickForm.tsx
index c1258460..99930e21 100644
--- a/packages/uniforms-antd/src/QuickForm.tsx
+++ b/packages/uniforms-antd/src/QuickForm.tsx
@@ -5,7 +5,7 @@ import BaseForm from './BaseForm';
 import ErrorsField from './ErrorsField';
 import SubmitField from './SubmitField';
 
-function Quick(parent: any): any {
+function Quick(parent: any) {
   class _ extends QuickForm.Quick(parent) {
     static Quick = Quick;
 
@@ -22,7 +22,7 @@ function Quick(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as QuickForm;
 }
 
 export default Quick(BaseForm);
diff --git a/packages/uniforms-antd/src/ValidatedForm.tsx b/packages/uniforms-antd/src/ValidatedForm.tsx
index 15aa5dbb..fa18a2d2 100644
--- a/packages/uniforms-antd/src/ValidatedForm.tsx
+++ b/packages/uniforms-antd/src/ValidatedForm.tsx
@@ -2,12 +2,12 @@ import { ValidatedForm } from 'uniforms';
 
 import BaseForm from './BaseForm';
 
-function Validated(parent: any): any {
+function Validated(parent: any) {
   class _ extends ValidatedForm.Validated(parent) {
     static Validated = Validated;
   }
 
-  return _;
+  return (_ as unknown) as ValidatedForm;
 }
 
 export default Validated(BaseForm);
diff --git a/packages/uniforms-bootstrap3/src/AutoForm.tsx b/packages/uniforms-bootstrap3/src/AutoForm.tsx
index a8f25da9..dd83b25b 100644
--- a/packages/uniforms-bootstrap3/src/AutoForm.tsx
+++ b/packages/uniforms-bootstrap3/src/AutoForm.tsx
@@ -2,12 +2,12 @@ import { AutoForm } from 'uniforms';
 
 import ValidatedQuickForm from './ValidatedQuickForm';
 
-function Auto(parent: any): any {
+function Auto(parent: any) {
   class _ extends AutoForm.Auto(parent) {
     static Auto = Auto;
   }
 
-  return _;
+  return (_ as unknown) as AutoForm;
 }
 
 export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-bootstrap3/src/BaseForm.tsx b/packages/uniforms-bootstrap3/src/BaseForm.tsx
index 18fb8028..626849a4 100644
--- a/packages/uniforms-bootstrap3/src/BaseForm.tsx
+++ b/packages/uniforms-bootstrap3/src/BaseForm.tsx
@@ -1,7 +1,7 @@
 import classnames from 'classnames';
 import { BaseForm } from 'uniforms';
 
-function Bootstrap3(parent: any): any {
+function Bootstrap3(parent: any) {
   class _ extends parent {
     static Bootstrap3 = Bootstrap3;
 
@@ -34,7 +34,7 @@ function Bootstrap3(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as typeof BaseForm;
 }
 
 export default Bootstrap3(BaseForm);
diff --git a/packages/uniforms-bootstrap3/src/QuickForm.tsx b/packages/uniforms-bootstrap3/src/QuickForm.tsx
index c1258460..99930e21 100644
--- a/packages/uniforms-bootstrap3/src/QuickForm.tsx
+++ b/packages/uniforms-bootstrap3/src/QuickForm.tsx
@@ -5,7 +5,7 @@ import BaseForm from './BaseForm';
 import ErrorsField from './ErrorsField';
 import SubmitField from './SubmitField';
 
-function Quick(parent: any): any {
+function Quick(parent: any) {
   class _ extends QuickForm.Quick(parent) {
     static Quick = Quick;
 
@@ -22,7 +22,7 @@ function Quick(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as QuickForm;
 }
 
 export default Quick(BaseForm);
diff --git a/packages/uniforms-bootstrap3/src/ValidatedForm.tsx b/packages/uniforms-bootstrap3/src/ValidatedForm.tsx
index 15aa5dbb..fa18a2d2 100644
--- a/packages/uniforms-bootstrap3/src/ValidatedForm.tsx
+++ b/packages/uniforms-bootstrap3/src/ValidatedForm.tsx
@@ -2,12 +2,12 @@ import { ValidatedForm } from 'uniforms';
 
 import BaseForm from './BaseForm';
 
-function Validated(parent: any): any {
+function Validated(parent: any) {
   class _ extends ValidatedForm.Validated(parent) {
     static Validated = Validated;
   }
 
-  return _;
+  return (_ as unknown) as ValidatedForm;
 }
 
 export default Validated(BaseForm);
diff --git a/packages/uniforms-bootstrap4/src/AutoForm.tsx b/packages/uniforms-bootstrap4/src/AutoForm.tsx
index a8f25da9..dd83b25b 100644
--- a/packages/uniforms-bootstrap4/src/AutoForm.tsx
+++ b/packages/uniforms-bootstrap4/src/AutoForm.tsx
@@ -2,12 +2,12 @@ import { AutoForm } from 'uniforms';
 
 import ValidatedQuickForm from './ValidatedQuickForm';
 
-function Auto(parent: any): any {
+function Auto(parent: any) {
   class _ extends AutoForm.Auto(parent) {
     static Auto = Auto;
   }
 
-  return _;
+  return (_ as unknown) as AutoForm;
 }
 
 export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-bootstrap4/src/BaseForm.tsx b/packages/uniforms-bootstrap4/src/BaseForm.tsx
index 711059c0..372bf8b2 100644
--- a/packages/uniforms-bootstrap4/src/BaseForm.tsx
+++ b/packages/uniforms-bootstrap4/src/BaseForm.tsx
@@ -2,7 +2,7 @@ import classnames from 'classnames';
 import omit from 'lodash/omit';
 import { BaseForm } from 'uniforms';
 
-function Bootstrap4(parent: any): any {
+function Bootstrap4(parent: any) {
   class _ extends parent {
     static Bootstrap4 = Bootstrap4;
 
@@ -23,7 +23,7 @@ function Bootstrap4(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as typeof BaseForm;
 }
 
 export default Bootstrap4(BaseForm);
diff --git a/packages/uniforms-bootstrap4/src/QuickForm.tsx b/packages/uniforms-bootstrap4/src/QuickForm.tsx
index c1258460..99930e21 100644
--- a/packages/uniforms-bootstrap4/src/QuickForm.tsx
+++ b/packages/uniforms-bootstrap4/src/QuickForm.tsx
@@ -5,7 +5,7 @@ import BaseForm from './BaseForm';
 import ErrorsField from './ErrorsField';
 import SubmitField from './SubmitField';
 
-function Quick(parent: any): any {
+function Quick(parent: any) {
   class _ extends QuickForm.Quick(parent) {
     static Quick = Quick;
 
@@ -22,7 +22,7 @@ function Quick(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as QuickForm;
 }
 
 export default Quick(BaseForm);
diff --git a/packages/uniforms-bootstrap4/src/ValidatedForm.tsx b/packages/uniforms-bootstrap4/src/ValidatedForm.tsx
index 15aa5dbb..fa18a2d2 100644
--- a/packages/uniforms-bootstrap4/src/ValidatedForm.tsx
+++ b/packages/uniforms-bootstrap4/src/ValidatedForm.tsx
@@ -2,12 +2,12 @@ import { ValidatedForm } from 'uniforms';
 
 import BaseForm from './BaseForm';
 
-function Validated(parent: any): any {
+function Validated(parent: any) {
   class _ extends ValidatedForm.Validated(parent) {
     static Validated = Validated;
   }
 
-  return _;
+  return (_ as unknown) as ValidatedForm;
 }
 
 export default Validated(BaseForm);
diff --git a/packages/uniforms-bootstrap5/src/AutoForm.tsx b/packages/uniforms-bootstrap5/src/AutoForm.tsx
index a8f25da9..dd83b25b 100644
--- a/packages/uniforms-bootstrap5/src/AutoForm.tsx
+++ b/packages/uniforms-bootstrap5/src/AutoForm.tsx
@@ -2,12 +2,12 @@ import { AutoForm } from 'uniforms';
 
 import ValidatedQuickForm from './ValidatedQuickForm';
 
-function Auto(parent: any): any {
+function Auto(parent: any) {
   class _ extends AutoForm.Auto(parent) {
     static Auto = Auto;
   }
 
-  return _;
+  return (_ as unknown) as AutoForm;
 }
 
 export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-bootstrap5/src/BaseForm.tsx b/packages/uniforms-bootstrap5/src/BaseForm.tsx
index 2b99b731..7a93c475 100644
--- a/packages/uniforms-bootstrap5/src/BaseForm.tsx
+++ b/packages/uniforms-bootstrap5/src/BaseForm.tsx
@@ -2,7 +2,7 @@ import classnames from 'classnames';
 import omit from 'lodash/omit';
 import { BaseForm } from 'uniforms';
 
-function Bootstrap5(parent: any): any {
+function Bootstrap5(parent: any) {
   class _ extends parent {
     static Bootstrap5 = Bootstrap5;
 
@@ -23,7 +23,7 @@ function Bootstrap5(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as typeof BaseForm;
 }
 
 export default Bootstrap5(BaseForm);
diff --git a/packages/uniforms-bootstrap5/src/QuickForm.tsx b/packages/uniforms-bootstrap5/src/QuickForm.tsx
index c1258460..99930e21 100644
--- a/packages/uniforms-bootstrap5/src/QuickForm.tsx
+++ b/packages/uniforms-bootstrap5/src/QuickForm.tsx
@@ -5,7 +5,7 @@ import BaseForm from './BaseForm';
 import ErrorsField from './ErrorsField';
 import SubmitField from './SubmitField';
 
-function Quick(parent: any): any {
+function Quick(parent: any) {
   class _ extends QuickForm.Quick(parent) {
     static Quick = Quick;
 
@@ -22,7 +22,7 @@ function Quick(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as QuickForm;
 }
 
 export default Quick(BaseForm);
diff --git a/packages/uniforms-bootstrap5/src/ValidatedForm.tsx b/packages/uniforms-bootstrap5/src/ValidatedForm.tsx
index 15aa5dbb..fa18a2d2 100644
--- a/packages/uniforms-bootstrap5/src/ValidatedForm.tsx
+++ b/packages/uniforms-bootstrap5/src/ValidatedForm.tsx
@@ -2,12 +2,12 @@ import { ValidatedForm } from 'uniforms';
 
 import BaseForm from './BaseForm';
 
-function Validated(parent: any): any {
+function Validated(parent: any) {
   class _ extends ValidatedForm.Validated(parent) {
     static Validated = Validated;
   }
 
-  return _;
+  return (_ as unknown) as ValidatedForm;
 }
 
 export default Validated(BaseForm);
diff --git a/packages/uniforms-bridge-json-schema/src/JSONSchemaBridge.ts b/packages/uniforms-bridge-json-schema/src/JSONSchemaBridge.ts
index 3eab01ba..92ca7647 100644
--- a/packages/uniforms-bridge-json-schema/src/JSONSchemaBridge.ts
+++ b/packages/uniforms-bridge-json-schema/src/JSONSchemaBridge.ts
@@ -35,13 +35,16 @@ function resolveRef(reference: string, schema: Record<string, any>) {
 function resolveRefIfNeeded(
   partial: Record<string, any>,
   schema: Record<string, any>,
-) {
-  if (partial.$ref) {
-    partial = Object.assign({}, partial, resolveRef(partial.$ref, schema));
-    delete partial.$ref;
+): Record<string, any> {
+  if (!('$ref' in partial)) {
+    return partial;
   }
 
-  return partial;
+  const { $ref, ...partialWithoutRef } = partial;
+  return resolveRefIfNeeded(
+    Object.assign({}, partialWithoutRef, resolveRef($ref, schema)),
+    schema,
+  );
 }
 
 const partialNames = ['allOf', 'anyOf', 'oneOf'];
diff --git a/packages/uniforms-material/src/AutoForm.tsx b/packages/uniforms-material/src/AutoForm.tsx
index a8f25da9..dd83b25b 100644
--- a/packages/uniforms-material/src/AutoForm.tsx
+++ b/packages/uniforms-material/src/AutoForm.tsx
@@ -2,12 +2,12 @@ import { AutoForm } from 'uniforms';
 
 import ValidatedQuickForm from './ValidatedQuickForm';
 
-function Auto(parent: any): any {
+function Auto(parent: any) {
   class _ extends AutoForm.Auto(parent) {
     static Auto = Auto;
   }
 
-  return _;
+  return (_ as unknown) as AutoForm;
 }
 
 export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-material/src/BaseForm.tsx b/packages/uniforms-material/src/BaseForm.tsx
index 8ee86a43..18901966 100644
--- a/packages/uniforms-material/src/BaseForm.tsx
+++ b/packages/uniforms-material/src/BaseForm.tsx
@@ -1,13 +1,13 @@
 import { BaseForm } from 'uniforms';
 
-function Material(parent: any): any {
+function Material(parent: any) {
   class _ extends parent {
     static Material = Material;
 
     static displayName = `Material${parent.displayName}`;
   }
 
-  return _;
+  return (_ as unknown) as typeof BaseForm;
 }
 
 export default Material(BaseForm);
diff --git a/packages/uniforms-material/src/QuickForm.tsx b/packages/uniforms-material/src/QuickForm.tsx
index c1258460..99930e21 100644
--- a/packages/uniforms-material/src/QuickForm.tsx
+++ b/packages/uniforms-material/src/QuickForm.tsx
@@ -5,7 +5,7 @@ import BaseForm from './BaseForm';
 import ErrorsField from './ErrorsField';
 import SubmitField from './SubmitField';
 
-function Quick(parent: any): any {
+function Quick(parent: any) {
   class _ extends QuickForm.Quick(parent) {
     static Quick = Quick;
 
@@ -22,7 +22,7 @@ function Quick(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as QuickForm;
 }
 
 export default Quick(BaseForm);
diff --git a/packages/uniforms-material/src/ValidatedForm.tsx b/packages/uniforms-material/src/ValidatedForm.tsx
index 15aa5dbb..fa18a2d2 100644
--- a/packages/uniforms-material/src/ValidatedForm.tsx
+++ b/packages/uniforms-material/src/ValidatedForm.tsx
@@ -2,12 +2,12 @@ import { ValidatedForm } from 'uniforms';
 
 import BaseForm from './BaseForm';
 
-function Validated(parent: any): any {
+function Validated(parent: any) {
   class _ extends ValidatedForm.Validated(parent) {
     static Validated = Validated;
   }
 
-  return _;
+  return (_ as unknown) as ValidatedForm;
 }
 
 export default Validated(BaseForm);
diff --git a/packages/uniforms-semantic/src/AutoForm.tsx b/packages/uniforms-semantic/src/AutoForm.tsx
index a8f25da9..dd83b25b 100644
--- a/packages/uniforms-semantic/src/AutoForm.tsx
+++ b/packages/uniforms-semantic/src/AutoForm.tsx
@@ -2,12 +2,12 @@ import { AutoForm } from 'uniforms';
 
 import ValidatedQuickForm from './ValidatedQuickForm';
 
-function Auto(parent: any): any {
+function Auto(parent: any) {
   class _ extends AutoForm.Auto(parent) {
     static Auto = Auto;
   }
 
-  return _;
+  return (_ as unknown) as AutoForm;
 }
 
 export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-semantic/src/BaseForm.tsx b/packages/uniforms-semantic/src/BaseForm.tsx
index c850a34a..d6a1ad99 100644
--- a/packages/uniforms-semantic/src/BaseForm.tsx
+++ b/packages/uniforms-semantic/src/BaseForm.tsx
@@ -1,7 +1,7 @@
 import classnames from 'classnames';
 import { BaseForm } from 'uniforms';
 
-function Semantic(parent: any): any {
+function Semantic(parent: any) {
   class _ extends parent {
     static Semantic = Semantic;
 
@@ -18,7 +18,7 @@ function Semantic(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as typeof BaseForm;
 }
 
 export default Semantic(BaseForm);
diff --git a/packages/uniforms-semantic/src/QuickForm.tsx b/packages/uniforms-semantic/src/QuickForm.tsx
index c1258460..99930e21 100644
--- a/packages/uniforms-semantic/src/QuickForm.tsx
+++ b/packages/uniforms-semantic/src/QuickForm.tsx
@@ -5,7 +5,7 @@ import BaseForm from './BaseForm';
 import ErrorsField from './ErrorsField';
 import SubmitField from './SubmitField';
 
-function Quick(parent: any): any {
+function Quick(parent: any) {
   class _ extends QuickForm.Quick(parent) {
     static Quick = Quick;
 
@@ -22,7 +22,7 @@ function Quick(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as QuickForm;
 }
 
 export default Quick(BaseForm);
diff --git a/packages/uniforms-semantic/src/ValidatedForm.tsx b/packages/uniforms-semantic/src/ValidatedForm.tsx
index 15aa5dbb..fa18a2d2 100644
--- a/packages/uniforms-semantic/src/ValidatedForm.tsx
+++ b/packages/uniforms-semantic/src/ValidatedForm.tsx
@@ -2,12 +2,12 @@ import { ValidatedForm } from 'uniforms';
 
 import BaseForm from './BaseForm';
 
-function Validated(parent: any): any {
+function Validated(parent: any) {
   class _ extends ValidatedForm.Validated(parent) {
     static Validated = Validated;
   }
 
-  return _;
+  return (_ as unknown) as ValidatedForm;
 }
 
 export default Validated(BaseForm);
diff --git a/packages/uniforms-unstyled/src/AutoForm.tsx b/packages/uniforms-unstyled/src/AutoForm.tsx
index a8f25da9..dd83b25b 100644
--- a/packages/uniforms-unstyled/src/AutoForm.tsx
+++ b/packages/uniforms-unstyled/src/AutoForm.tsx
@@ -2,12 +2,12 @@ import { AutoForm } from 'uniforms';
 
 import ValidatedQuickForm from './ValidatedQuickForm';
 
-function Auto(parent: any): any {
+function Auto(parent: any) {
   class _ extends AutoForm.Auto(parent) {
     static Auto = Auto;
   }
 
-  return _;
+  return (_ as unknown) as AutoForm;
 }
 
 export default Auto(ValidatedQuickForm);
diff --git a/packages/uniforms-unstyled/src/BaseForm.tsx b/packages/uniforms-unstyled/src/BaseForm.tsx
index b1a6bb8a..2dd41947 100644
--- a/packages/uniforms-unstyled/src/BaseForm.tsx
+++ b/packages/uniforms-unstyled/src/BaseForm.tsx
@@ -1,13 +1,13 @@
 import { BaseForm } from 'uniforms';
 
-function Unstyled(parent: any): any {
+function Unstyled(parent: any) {
   class _ extends parent {
     static Unstyled = Unstyled;
 
     static displayName = `Unstyled${parent.displayName}`;
   }
 
-  return _;
+  return (_ as unknown) as typeof BaseForm;
 }
 
 export default Unstyled(BaseForm);
diff --git a/packages/uniforms-unstyled/src/QuickForm.tsx b/packages/uniforms-unstyled/src/QuickForm.tsx
index c1258460..99930e21 100644
--- a/packages/uniforms-unstyled/src/QuickForm.tsx
+++ b/packages/uniforms-unstyled/src/QuickForm.tsx
@@ -5,7 +5,7 @@ import BaseForm from './BaseForm';
 import ErrorsField from './ErrorsField';
 import SubmitField from './SubmitField';
 
-function Quick(parent: any): any {
+function Quick(parent: any) {
   class _ extends QuickForm.Quick(parent) {
     static Quick = Quick;
 
@@ -22,7 +22,7 @@ function Quick(parent: any): any {
     }
   }
 
-  return _;
+  return (_ as unknown) as QuickForm;
 }
 
 export default Quick(BaseForm);
diff --git a/packages/uniforms-unstyled/src/ValidatedForm.tsx b/packages/uniforms-unstyled/src/ValidatedForm.tsx
index 15aa5dbb..fa18a2d2 100644
--- a/packages/uniforms-unstyled/src/ValidatedForm.tsx
+++ b/packages/uniforms-unstyled/src/ValidatedForm.tsx
@@ -2,12 +2,12 @@ import { ValidatedForm } from 'uniforms';
 
 import BaseForm from './BaseForm';
 
-function Validated(parent: any): any {
+function Validated(parent: any) {
   class _ extends ValidatedForm.Validated(parent) {
     static Validated = Validated;
   }
 
-  return _;
+  return (_ as unknown) as ValidatedForm;
 }
 
 export default Validated(BaseForm);
diff --git a/packages/uniforms/src/changedKeys.ts b/packages/uniforms/src/changedKeys.ts
index c293d534..26da23d9 100644
--- a/packages/uniforms/src/changedKeys.ts
+++ b/packages/uniforms/src/changedKeys.ts
@@ -2,14 +2,18 @@ import isEqual from 'lodash/isEqual';
 
 import { joinName } from './joinName';
 
+function isObject(value: unknown): value is Record<string, unknown> {
+  return !!value && value === Object(value) && !(value instanceof Date);
+}
+
 // eslint-disable-next-line complexity
-export function changedKeys<T>(root: string, valueA?: T, valueB?: T) {
-  if (!valueA || valueA !== Object(valueA) || valueA instanceof Date) {
+export function changedKeys(root: string, valueA?: unknown, valueB?: unknown) {
+  if (!isObject(valueA) || (valueB && typeof valueA !== typeof valueB)) {
     return isEqual(valueA, valueB) ? [] : [root];
   }
 
   const changed = [root];
-  if (valueB) {
+  if (isObject(valueB)) {
     for (const key in valueA) {
       if (!(key in valueB) || !isEqual(valueA[key], valueB[key])) {
         changed.push(joinName(root, key));
diff --git a/website/lib/universal.tsx b/website/lib/universal.tsx
index e91509d3..edda486a 100644
--- a/website/lib/universal.tsx
+++ b/website/lib/universal.tsx
@@ -44,9 +44,10 @@ export const themes = {
 export const themeContext = createContext<keyof typeof themes>('unstyled');
 
 function _createThemedComponent(component: keyof typeof unstyled) {
-  return function ThemedComponent(props: Record<string, any>) {
+  return function ThemedComponent(props: Record<string, unknown>) {
     const theme = useContext(themeContext);
-    const Component = themes[theme][component];
+    // FIXME: Form prop errors due to `props` having no strict type here.
+    const Component: any = themes[theme][component];
     return <Component key={theme} {...props} />;
   };
 }


Test patch:
diff --git a/packages/uniforms-bridge-json-schema/__tests__/JSONSchemaBridge.ts b/packages/uniforms-bridge-json-schema/__tests__/JSONSchemaBridge.ts
index 3f196563..ea176f4e 100644
--- a/packages/uniforms-bridge-json-schema/__tests__/JSONSchemaBridge.ts
+++ b/packages/uniforms-bridge-json-schema/__tests__/JSONSchemaBridge.ts
@@ -24,11 +24,13 @@ describe('JSONSchemaBridge', () => {
         type: 'object',
         properties: {
           firstName: { $ref: '#/definitions/firstName' },
+          middleName: { $ref: '#/definitions/middleName' },
           lastName: { $ref: '#/definitions/firstName' },
         },
         required: ['lastName'],
       },
       firstName: { type: 'string', default: 'John' },
+      middleName: { $ref: '#/definitions/lastName' },
       lastName: { type: 'string' },
       recursive: {
         type: 'object',
@@ -474,6 +476,12 @@ describe('JSONSchemaBridge', () => {
       });
     });
 
+    it('returns correct definition ($ref pointing to $ref)', () => {
+      expect(bridge.getField('personalData.middleName')).toEqual({
+        type: 'string',
+      });
+    });
+
     it('returns correct definition (array tuple)', () => {
       expect(bridge.getField('dateOfBirthTuple.1')).toEqual({ type: 'string' });
     });
diff --git a/packages/uniforms/__tests__/changedKeys.ts b/packages/uniforms/__tests__/changedKeys.ts
index 0002969b..80e2612f 100644
--- a/packages/uniforms/__tests__/changedKeys.ts
+++ b/packages/uniforms/__tests__/changedKeys.ts
@@ -95,4 +95,21 @@ describe('changedKeys', () => {
       expect(changedKeys('a', 'pe', 'no')).toEqual(['a']);
     });
   });
+
+  it('works with changing value types', () => {
+    expect(changedKeys('a', '1', 1)).toEqual(['a']);
+    expect(changedKeys('a', 1, '1')).toEqual(['a']);
+    expect(changedKeys('a', 'true', true)).toEqual(['a']);
+    expect(changedKeys('a', true, 'true')).toEqual(['a']);
+    expect(changedKeys('a', 'false', false)).toEqual(['a']);
+    expect(changedKeys('a', false, 'false')).toEqual(['a']);
+    expect(changedKeys('a', '0', null)).toEqual(['a']);
+    expect(changedKeys('a', null, '0')).toEqual(['a']);
+    expect(changedKeys('a', Date.now(), new Date())).toEqual(['a']);
+    expect(changedKeys('a', new Date(), Date.now())).toEqual(['a']);
+    expect(changedKeys('a', 'value', { key: 'value' })).toEqual(['a']);
+    expect(changedKeys('a', { key: 'value' }, 'value')).toEqual(['a']);
+    expect(changedKeys('a', 'value', ['value'])).toEqual(['a']);
+    expect(changedKeys('a', ['value'], 'value')).toEqual(['a']);
+  });
 });