Skip to content

Commit

Permalink
Refine Terminology Around Params
Browse files Browse the repository at this point in the history
  • Loading branch information
harrysolovay committed Nov 26, 2024
1 parent 6e0c581 commit 314fa4c
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 149 deletions.
3 changes: 3 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ function patternsItems(): DefaultTheme.SidebarItem[] {
collapsed: false,
items: [
{ text: "Overview", link: "patterns" },
{ text: "Standard Patterns", link: "patterns/std" },
{ text: "Authoring", link: "patterns/authoring" },
{ text: "Conventions", link: "patterns/conventions" },
{ text: "Custom Types", link: "patterns/custom-types" },
],
},
{
Expand Down
10 changes: 5 additions & 5 deletions docs/common-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Therefore, an error is produced if you try to create a `ResponseFormat` with an
import { ResponseFormat, T } from "structured-outputs"
// ---cut---
const Root = T.object({
value: T.string`Placeheld: ${"placeheld_key"}.`,
value: T.string`Arg: ${"param_key"}.`,
})

ResponseFormat("my_format", Root)
Expand All @@ -47,10 +47,10 @@ To solve this error, fill in the missing parameter.
import { ResponseFormat, T } from "structured-outputs"

const Root = T.object({
value: T.string`Placeheld: ${"placeheld_key"}.`,
value: T.string`Arg: ${"param_key"}.`,
})
// ---cut---
ResponseFormat("my_format", Root.fill({ placeheld_key: "missing context" }))
ResponseFormat("my_format", Root.fill({ param_key: "missing context" }))
```

## Context Parameter Keys
Expand All @@ -64,9 +64,9 @@ parameterize context with a widened `number`, `string` or `symbol`.
// @errors: 2345
import { T } from "structured-outputs"
// ---cut---
declare const my_key: string
declare const param_key: string

const MyType = T.string`Placeheld: ${my_key}`
const MyType = T.string`Arg: ${param_key}`
```

If you see this error, it may indicate that you are trying to interpolate some raw context text
Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ const Contact = T.object({

## Parameterized Context

Placehold context to be filled in later. This simplifies reuse of types for different generation use
cases.
Parameterized context to be filled in later (even when contained within any number of wrapper
types). This simplifies reuse of types for different generation use cases.

```ts twoslash
import { T } from "structured-outputs"
Expand Down
140 changes: 20 additions & 120 deletions docs/patterns/authoring.md
Original file line number Diff line number Diff line change
@@ -1,159 +1,59 @@
---
prev:
text: Patterns Overview
link: patterns
next: false
text: Standard Patterns
link: patterns/std
next:
text: Pattern Conventions
link: patterns/conventions
---

# Authoring Patterns

## Functional Patterns

Functional patterns are simply functions that return `Ty`s.

### Basic Example
## Atomic Patterns

For example, we can create a `Range` pattern, which attaches important context to a `number`.
A pattern can be as simple as attaching some context to a type.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
function Range(from: number, to: number) {
return T.number`A number between ${"from"} and ${"to"}`.fill({ from, to })
}
export const Song = T.string`Ensure this text is a 16-bars song.`
```

### `Ty`s as Arguments
## Parameterized Context

In some cases, you may want to accept `Ty`s as arguments, which inform the type of the returned
`Ty`.
Patterns can contain unfilled/parameterized context.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---

function MostUnlikely<X extends T.Ty>(ty: X) {
return ty`Ensure that this generated type is the most unlikely instance of itself.`
}
export const Song = T.string`Ensure this text is a 16-bars song in the style of ${"song_style"}.`
```

## Standard Patterns

### `Option`

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
const Critique = T.Option(T.string)

Critique
// ^?
```

<br />
<br />
<br />
<br />
<br />
<br />
<br />

### `Date`
## Functional Patterns

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
T.Date
```
Functional patterns are simply functions that return types.

## Library Placeholder Convention
### Basic Example

If you are publishing a pattern library of placeholder-bearing types, you may want to specify
placeholder keys as symbols, which you export from your library's entrypoint.
For example, we can create a `Range` pattern, which attaches important context to a `number`.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
export namespace P {
export const grade = Symbol()
export function Range(from: number, to: number) {
return T.number`A number between ${"from"} and ${"to"}`.fill({ from, to })
}

export const SchoolCurriculumSubject = T.string`The school curriculum for grade ${P.grade}.`
```

> Note: a pattern library may include many placeholder keys. To simplify end-developer usage, we
> place all keys under a single library-wide `P` namespace.
### Types as Arguments

## JSR Slow Types

JSR is a TypeScript package registry created by the Deno team. In the case that you wish to publish
your pattern library to JSR, be weary of [slow types](https://jsr.io/docs/about-slow-types).

In the previous code block––for example––we would need to add an explicit type to avoid static
analysis degradation.
You may want to accept types as arguments, which inform the type of the return.

```ts twoslash
import { T } from "structured-outputs"

export namespace P {
export const grade = Symbol()
}
// ---cut---
const SchoolCurriculumSubject: T.Ty<string, typeof P.grade, false> = T
.string`The school curriculum for grade ${P.grade}.`
```

If we are creating a functional pattern, we explicitly return or unwrap type arguments.

In the following example, the return type is simply the sole parameter type.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
export function MostUnlikely<T, P extends keyof any, R extends boolean>(
ty: T.Ty<T, P, R>,
): T.Ty<T, P, R> {
function MostUnlikely<X extends T.Ty>(ty: X) {
return ty`Ensure that this generated type is the most unlikely instance of itself.`
}
```

However, we may encounter cases which require us to unwrap the `Ty` type parameter(s) and explicitly
form a return `Ty` type.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
export namespace P {
export const Tone = Symbol()
}

export function WithTone<T, P extends keyof any, R extends boolean>(
ty: T.Ty<T, P, R>,
): T.Ty<T, P | typeof P.Tone> {
return ty`Generate with a tone of ${P.Tone}.`
}
```

## Custom Types

In the case that you need to implement a custom type, this may indicate a current shortcoming of
`structured-outputs` and you're encouraged to
[file an issue](https://github.com/harrysolovay/structured-outputs/issues/new). That being said,
here's how you can create a custom type.

Let's create an `any` type (not intended to be used in production).

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
const any: T.Ty<any, never, false> = T.Ty(
() => ({
type: "object",
properties: {},
}),
false,
)
```

You could similarly create a functional pattern, which accepts arguments and uses them to form the
returned `Ty`.
78 changes: 78 additions & 0 deletions docs/patterns/conventions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
prev:
text: Authoring Patterns
link: patterns/authoring
next:
text: Custom Types
link: patterns/custom-types
---

# Conventions

## Exposing Parameter Keys

If you are publishing a pattern library of parameterized types, you may want to specify parameter
keys as symbols, which you export from your library's entrypoint.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
export namespace P {
export const grade = Symbol()
}

export const SchoolCurriculumSubject = T.string`The school curriculum for grade ${P.grade}.`
```

> Note: a pattern library may include many parameter keys. To simplify end-developer usage, we place
> all keys under a single library-wide `P` namespace.
## Accounting For JSR Slow Types

JSR is a TypeScript package registry created by the Deno team. In the case that you wish to publish
your pattern library to JSR, be weary of [slow types](https://jsr.io/docs/about-slow-types).

In the previous code block––for example––we would need to add an explicit type to avoid static
analysis degradation.

```ts twoslash
import { T } from "structured-outputs"

export namespace P {
export const grade = Symbol()
}
// ---cut---
const SchoolCurriculumSubject: T.Ty<string, typeof P.grade, false> = T
.string`The school curriculum for grade ${P.grade}.`
```

If we are creating a functional pattern, we explicitly return or unwrap type arguments.

In the following example, the return type is simply the sole parameter type.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
export function MostUnlikely<T, P extends keyof any, R extends boolean>(
ty: T.Ty<T, P, R>,
): T.Ty<T, P, R> {
return ty`Ensure that this generated type is the most unlikely instance of itself.`
}
```

However, we may encounter cases which require us to unwrap the `Ty` type parameter(s) and explicitly
form a return `Ty` type.

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
export namespace P {
export const Tone = Symbol()
}

export function WithTone<T, P extends keyof any, R extends boolean>(
ty: T.Ty<T, P, R>,
): T.Ty<T, P | typeof P.Tone> {
return ty`Generate with a tone of ${P.Tone}.`
}
```
30 changes: 30 additions & 0 deletions docs/patterns/custom-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
prev:
text: Pattern Conventions
link: patterns/conventions
next: false
---

# Custom Types

In the case that you need to implement a custom type, this may indicate a current shortcoming of
`structured-outputs` and you're encouraged to
[file an issue](https://github.com/harrysolovay/structured-outputs/issues/new). That being said,
here's how you can create a custom type.

Let's create an `any` type (not intended to be used in production).

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
const any: T.Ty<any, never, false> = T.Ty(
() => ({
type: "object",
properties: {},
}),
false,
)
```

You could similarly create a functional pattern, which accepts arguments and uses them to form the
returned `Ty`.
4 changes: 2 additions & 2 deletions docs/patterns/index.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
prev: false
next:
text: Authoring Patterns
link: patterns/authoring
text: Standard Patterns
link: patterns/std
---

# Patterns Overview
Expand Down
37 changes: 37 additions & 0 deletions docs/patterns/std.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
prev:
text: Patterns Overview
link: patterns
next:
text: Authoring Patterns
link: patterns/authoring
---

# Standard Patterns

## `Option`

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
const Critique = T.Option(T.string)

Critique
// ^?
```

<br />
<br />
<br />
<br />
<br />
<br />
<br />

## `Date`

```ts twoslash
import { T } from "structured-outputs"
// ---cut---
T.Date
```
Loading

0 comments on commit 314fa4c

Please sign in to comment.