-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(docs): Add discriminated union section (#3763)
- Loading branch information
Showing
2 changed files
with
219 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,227 @@ | ||
### Discriminated Unions | ||
The SDKs natively support discriminated unions. | ||
--- | ||
title: Discriminated Unions | ||
description: Fern SDKs include idiomatic support for discriminated unions | ||
--- | ||
|
||
```ts maxLines=0 {1} | ||
export type Shape = Triangle | Square; | ||
The SDKs natively support discriminated [unions](../../api-definition/fern/types#unions) for both OpenAPI and Fern APIs. | ||
|
||
export interface Triangle { | ||
type: "triangle"; | ||
a: number; | ||
b: number; | ||
c: number; | ||
<AccordionGroup> | ||
<Accordion title="Fern definition"> | ||
Discriminated unions are defined with the `union` key. For example, a simple | ||
`Shape` type that can either be a `Triangle` or a `Square` can be defined as follows: | ||
|
||
<CodeBlock title="fern/definition/shape.yml"> | ||
```yaml | ||
types: | ||
Shape: | ||
union: | ||
triangle: Triangle | ||
square: Square | ||
|
||
Triangle: | ||
properties: | ||
a: double | ||
b: double | ||
c: double | ||
|
||
Square: | ||
properties: | ||
side: double | ||
``` | ||
</CodeBlock> | ||
With this, the JSON representation for a `Shape` looks like the following: | ||
|
||
<CodeBlock title="triangle.json"> | ||
```json | ||
{ | ||
"type": "triangle", | ||
"a": 3, | ||
"b": 4, | ||
"c": 5 | ||
} | ||
``` | ||
</CodeBlock> | ||
|
||
or | ||
|
||
export interface Square { | ||
type: "square"; | ||
/* length of a single side */ | ||
side: number; | ||
<CodeBlock title="square.json"> | ||
```json | ||
{ | ||
"type": "sqaure", | ||
"side": 5 | ||
} | ||
``` | ||
</CodeBlock> | ||
</Accordion> | ||
|
||
Consumers can easily write branching logic by checking the discriminant. | ||
<Accordion title="OpenAPI spec"> | ||
Discriminated unions are defined with the `oneOf` and `anyOf` keys. For example, consider | ||
the following `Shape` definition: | ||
|
||
<CodeBlock title="openapi.yml"> | ||
```yaml | ||
components: | ||
schemas: | ||
Shape: | ||
oneOf: | ||
- $ref: "#/components/schemas/Triangle" | ||
- $ref: "#/components/schemas/Square" | ||
Triangle: | ||
type: object | ||
properties: | ||
type: | ||
type: string | ||
enum: | ||
- triangle | ||
a: | ||
type: number | ||
b: | ||
type: number | ||
c: | ||
type: number | ||
required: | ||
- type | ||
- a | ||
- b | ||
- c | ||
Square: | ||
type: object | ||
properties: | ||
type: | ||
type: string | ||
enum: | ||
- square | ||
side: | ||
type: number | ||
required: | ||
- type | ||
- side | ||
``` | ||
</CodeBlock> | ||
|
||
```ts {4, 6} | ||
import { Shape } from "sdk"; | ||
With this, the JSON representation for a `Shape` looks like the following: | ||
|
||
export function computeArea(shape: Shape): number { | ||
if (shape.type === "triangle") { | ||
// compute triangle area | ||
} else if (shape.type === "square") { | ||
// compute square area | ||
} | ||
<CodeBlock title="triangle.json"> | ||
```json | ||
{ | ||
"type": "triangle", | ||
"a": 3, | ||
"b": 4, | ||
"c": 5 | ||
} | ||
``` | ||
``` | ||
</CodeBlock> | ||
|
||
or | ||
|
||
<CodeBlock title="square.json"> | ||
```json | ||
{ | ||
"type": "sqaure", | ||
"side": 5 | ||
} | ||
``` | ||
</CodeBlock> | ||
</Accordion> | ||
</AccordionGroup> | ||
|
||
<Tabs> | ||
<Tab title="TypeScript"> | ||
|
||
```ts maxLines=0 {1} | ||
export type Shape = Triangle | Square; | ||
export interface Triangle { | ||
type: "triangle"; | ||
a: number; | ||
b: number; | ||
c: number; | ||
} | ||
export interface Square { | ||
type: "square"; | ||
side: number; | ||
} | ||
``` | ||
|
||
Callers can create a `Shape` object by simply constructing the appropriate type. For example, creating | ||
a `Triangle` shape looks like the following: | ||
|
||
```ts | ||
const shape: Shape = { | ||
type: "triangle", | ||
a: 3, | ||
b: 4, | ||
c: 5, | ||
}; | ||
``` | ||
|
||
Consumers can easily write branching logic by checking the discriminant. | ||
|
||
```ts {4, 6} | ||
import { Shape } from "sdk"; | ||
export function computeArea(shape: Shape): number { | ||
if (shape.type === "triangle") { | ||
// compute triangle area | ||
} else if (shape.type === "square") { | ||
// compute square area | ||
} | ||
} | ||
``` | ||
|
||
</Tab> | ||
|
||
<Tab title="Go"> | ||
|
||
Go does not have a built-in support for discriminated unions. However, you can define a union struct | ||
to achieve the same effect: | ||
|
||
```go maxLines=0 {1-5} | ||
type Shape struct { | ||
Type string | ||
Triangle *Triangle | ||
Square *Square | ||
} | ||
type Triangle struct { | ||
A float64 `json:"a" url:"a"` | ||
B float64 `json:"b" url:"b"` | ||
C float64 `json:"c" url:"c"` | ||
} | ||
|
||
type Square struct { | ||
Side float64 `json:"side" url:"side"` | ||
} | ||
``` | ||
|
||
Callers can create a `Shape` object by simply setting the appropriate key. For example, creating | ||
a `Triangle` shape looks like the following: | ||
|
||
```go | ||
shape := &Shape{ | ||
// You do not need to set the Type field manually, the SDK will automatically set it for you. | ||
Triangle: &Triangle{ | ||
A: 3, | ||
B: 4, | ||
C: 5, | ||
}, | ||
} | ||
``` | ||
|
||
Consumers can easily write a `switch` statement by checking the discriminant: | ||
|
||
```go {3, 5} | ||
func ComputeArea(shape *Shape) float64 { | ||
switch shape.Type { | ||
case "triangle": | ||
// compute triangle area | ||
case "square": | ||
// compute square areair | ||
} | ||
} | ||
``` | ||
|
||
</Tab> | ||
</Tabs> |