Skip to content

Commit

Permalink
document feature
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasAribart committed May 4, 2024
1 parent 067fda2 commit e806f2e
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 3 deletions.
58 changes: 55 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,9 @@ type Object = FromSchema<
// => { foo?: string; }
```

`FromSchema` partially supports the `additionalProperties` and `patternProperties` keywords:
`FromSchema` partially supports the `additionalProperties`, `patternProperties` and `unevaluatedProperties` keywords:

- `additionalProperties` can be used to deny additional properties.
- `additionalProperties` and `unevaluatedProperties` can be used to deny additional properties.

```typescript
const closedObjectSchema = {
Expand All @@ -387,6 +387,29 @@ type Object = FromSchema<typeof closedObjectSchema>;
// => { foo: string; bar?: number; }
```

```typescript
const closedObjectSchema = {
type: "object",
allOf: [
{
properties: {
foo: { type: "string" },
},
required: ["foo"],
},
{
properties: {
bar: { type: "number" },
},
},
],
unevaluatedProperties: false,
} as const;

type Object = FromSchema<typeof closedObjectSchema>;
// => { foo: string; bar?: number; }
```

- Used on their own, `additionalProperties` and/or `patternProperties` can be used to type unnamed properties.

```typescript
Expand All @@ -405,7 +428,36 @@ type Object = FromSchema<typeof openObjectSchema>;
// => { [x: string]: string | number | boolean }
```

- However, when used in combination with the `properties` keyword, extra properties will always be typed as `unknown` to avoid conflicts.
However:

- When used in combination with the `properties` keyword, extra properties will always be typed as `unknown` to avoid conflicts.

```typescript
const mixedObjectSchema = {
type: "object",
properties: {
foo: { enum: ["bar", "baz"] },
},
additionalProperties: { type: "string" },
} as const;

type Object = FromSchema<typeof mixedObjectSchema>;
// => { [x: string]: unknown; foo?: "bar" | "baz"; }
```

- Due to its context-dependent nature, `unevaluatedProperties` does not type extra-properties when used on its own. Use `additionalProperties` instead.

```typescript
const openObjectSchema = {
type: "object",
unevaluatedProperties: {
type: "boolean",
},
} as const;

type Object = FromSchema<typeof openObjectSchema>;
// => { [x: string]: unknown }
```

## Combining schemas

Expand Down
58 changes: 58 additions & 0 deletions src/tests/readme/object.type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,64 @@ type AssertObjectWithTypedAdditionalProperties = A.Equals<
const assertObjectWithTypedAdditionalProperties: AssertObjectWithTypedAdditionalProperties = 1;
assertObjectWithTypedAdditionalProperties;

// Mixed schema

const mixedObjectSchema = {
type: "object",
properties: {
foo: { enum: ["bar", "baz"] },
},
additionalProperties: { type: "string" },
} as const;

type ReceivedMixedObject = FromSchema<typeof mixedObjectSchema>;
type ExpectedMixedObject = { [x: string]: unknown; foo?: "bar" | "baz" };

type AssertMixedObject = A.Equals<ReceivedMixedObject, ExpectedMixedObject>;
const assertMixedObject: AssertMixedObject = 1;
assertMixedObject;

// Unevaluated properties schema

const closedObjectSchema = {
type: "object",
allOf: [
{
properties: {
foo: { type: "string" },
},
required: ["foo"],
},
{
properties: {
bar: { type: "number" },
},
},
],
unevaluatedProperties: false,
} as const;

type ReceivedClosedObject = FromSchema<typeof closedObjectSchema>;
type ExpectedClosedObject = { foo: string; bar?: number };

type AssertClosedObject = A.Equals<ReceivedClosedObject, ExpectedClosedObject>;
const assertClosedObject: AssertClosedObject = 1;
assertClosedObject;

const openObjectSchema = {
type: "object",
unevaluatedProperties: {
type: "boolean",
},
} as const;

type ReceivedOpenObject = FromSchema<typeof openObjectSchema>;
type ExpectedOpenObject = { [x: string]: unknown };

type AssertOpenObject = A.Equals<ReceivedOpenObject, ExpectedOpenObject>;
const assertOpenObject: AssertOpenObject = 1;
assertOpenObject;

// Defaulted property

const objectWithDefaultedPropertySchema = {
Expand Down

0 comments on commit e806f2e

Please sign in to comment.