Skip to content

Commit

Permalink
Schema: add Understanding Schema Declaration for New Data Types > Add… (
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti authored Jan 28, 2024
1 parent 6739685 commit 8b3cc96
Showing 1 changed file with 73 additions and 7 deletions.
80 changes: 73 additions & 7 deletions packages/schema/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3078,7 +3078,9 @@ import * as S from "@effect/schema/Schema";
const isFile = (input: unknown): input is File => input instanceof File;

// const FileFromSelf: S.Schema<never, File, File>
const FileFromSelf = S.declare(isFile).pipe(S.identifier("FileFromSelf"));
const FileFromSelf = S.declare(isFile, {
identifier: "FileFromSelf",
});

const parseSync = S.decodeUnknownSync(FileFromSelf);

Expand All @@ -3087,8 +3089,7 @@ console.log(parseSync(new File([], ""))); // File { size: 0, type: '', name: '',
parseSync(null);
/*
throws
Error: FileFromSelf
└─ Expected FileFromSelf, actual null
Error: Error: Expected FileFromSelf, actual null
*/
```

Expand All @@ -3097,7 +3098,6 @@ Error: FileFromSelf
Type constructors are generic types that take one or more types as arguments and return a new type. If you need to define a schema for a type constructor, you can use the `S.declare` constructor. Let's illustrate this with a schema for `ReadonlySet<A>`:

```ts
import * as Format from "@effect/schema/Format";
import * as ParseResult from "@effect/schema/ParseResult";
import * as S from "@effect/schema/Schema";

Expand Down Expand Up @@ -3133,8 +3133,11 @@ export const myReadonlySet = <R, I, A>(
return ParseResult.map(elements, (is): ReadonlySet<I> => new Set(is));
}
return ParseResult.fail(ParseResult.type(ast, input));
},
{
description: `ReadonlySet<${S.format(item)}>`,
}
).pipe(S.description(`ReadonlySet<${Format.format(item)}>`));
);

// const setOfNumbers: S.Schema<never, ReadonlySet<string>, ReadonlySet<number>>
const setOfNumbers = myReadonlySet(S.NumberFromString);
Expand All @@ -3146,8 +3149,7 @@ console.log(parseSync(new Set(["1", "2", "3"]))); // Set(3) { 1, 2, 3 }
parseSync(null);
/*
throws
Error: ReadonlySet<NumberFromString>
└─ Expected ReadonlySet<NumberFromString>, actual null
Error: Expected ReadonlySet<NumberFromString>, actual null
*/

parseSync(new Set(["1", null, "3"]));
Expand All @@ -3162,6 +3164,70 @@ Error: ReadonlySet<NumberFromString>
*/
```

## Adding Annotations

When you define a new data type, some compilers like `Arbitrary` or `Pretty` may not know how to handle the newly defined data. For instance:

```ts
import * as Arbitrary from "@effect/schema/Arbitrary";
import * as S from "@effect/schema/Schema";

const isFile = (input: unknown): input is File => input instanceof File;

const FileFromSelf = S.declare(isFile, {
identifier: "FileFromSelf",
});

// Create an Arbitrary instance for FileFromSelf schema
const arb = Arbitrary.make(FileFromSelf);
/*
throws:
Error: cannot build an Arbitrary for a declaration without annotations (FileFromSelf)
*/
```

In such cases, you need to provide annotations to ensure proper functionality:

```ts
import * as Arbitrary from "@effect/schema/Arbitrary";
import * as Pretty from "@effect/schema/Pretty";
import * as S from "@effect/schema/Schema";
import * as fc from "fast-check";

const isFile = (input: unknown): input is File => input instanceof File;

const FileFromSelf = S.declare(isFile, {
identifier: "FileFromSelf",
// Provide an arbitrary function to generate random File instances
arbitrary: () => (fc) =>
fc
.tuple(fc.string(), fc.string())
.map(([path, content]) => new File([content], path)),
// Provide a pretty function to generate human-readable representation of File instances
pretty: () => (file) => `File(${file.name})`,
});

// Create an Arbitrary instance for FileFromSelf schema
const arb = Arbitrary.make(FileFromSelf);

// Generate sample files using the Arbitrary instance
const files = fc.sample(arb(fc), 2);
console.log(files);
/*
Output:
[
File { size: 5, type: '', name: 'C', lastModified: 1706435571176 },
File { size: 1, type: '', name: '98Ggmc', lastModified: 1706435571176 }
]
*/

// Create a Pretty instance for FileFromSelf schema
const pretty = Pretty.make(FileFromSelf);

// Print human-readable representation of a file
console.log(pretty(files[0])); // "File(C)"
```

# Useful Examples

## Email
Expand Down

0 comments on commit 8b3cc96

Please sign in to comment.