Skip to content
This repository has been archived by the owner on Oct 4, 2023. It is now read-only.

Commit

Permalink
feat: added Types module (#461)
Browse files Browse the repository at this point in the history
  • Loading branch information
jessekelly881 committed Aug 31, 2023
1 parent ac156ef commit 41ddfb7
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 41 deletions.
5 changes: 5 additions & 0 deletions .changeset/many-geese-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/data": patch
---

added Types module
2 changes: 1 addition & 1 deletion docs/modules/Brand.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ This API is useful when you want to validate that the input data passes multiple
export declare const all: <Brands extends readonly [Brand.Constructor<any>, ...Brand.Constructor<any>[]]>(
...brands: Brand.EnsureCommonBase<Brands>
) => Brand.Constructor<
Brand.UnionToIntersection<
Types.UnionToIntersection<
{ [B in keyof Brands]: Brand.FromConstructor<Brands[B]> }[number]
> extends infer X extends Brand<any>
? X
Expand Down
17 changes: 3 additions & 14 deletions docs/modules/Data.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ Added in v1.0.0
- [models](#models)
- [Case (interface)](#case-interface)
- [Data (type alias)](#data-type-alias)
- [IsEqualTo (type alias)](#isequalto-type-alias)
- [TaggedEnum (type alias)](#taggedenum-type-alias)
- [utils](#utils)
- [Case (namespace)](#case-namespace)
Expand All @@ -49,7 +48,7 @@ Provides a constructor for a Case Class.

```ts
export declare const Class: new <A extends Record<string, any>>(
args: IsEqualTo<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
args: Types.Equals<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
) => Data<A>
```

Expand All @@ -65,7 +64,7 @@ Provides a Tagged constructor for a Case Class.
export declare const TaggedClass: <Key extends string>(
tag: Key
) => new <A extends Record<string, any>>(
args: IsEqualTo<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
args: Types.Equals<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
) => Data<A & { _tag: Key }>
```

Expand Down Expand Up @@ -240,16 +239,6 @@ export type Data<A extends Readonly<Record<string, any>> | ReadonlyArray<any>> =
Added in v1.0.0
## IsEqualTo (type alias)
**Signature**
```ts
export type IsEqualTo<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false
```
Added in v1.0.0
## TaggedEnum (type alias)
Create a tagged enum data type, which is a union of `Data` structs.
Expand Down Expand Up @@ -280,7 +269,7 @@ type HttpErrorPlain =
```ts
export type TaggedEnum<A extends Record<string, Record<string, any>>> = {
readonly [Tag in keyof A]: Data<Simplify<Readonly<A[Tag]> & { readonly _tag: Tag }>>
readonly [Tag in keyof A]: Data<Readonly<Types.Simplify<A[Tag] & { _tag: Tag }>>>
}[keyof A]
```
Expand Down
191 changes: 191 additions & 0 deletions docs/modules/Types.ts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
---
title: Types.ts
nav_order: 47
parent: Modules
---

## Types overview

A collection of types that are commonly used types.

Added in v1.0.0

---

<h2 class="text-delta">Table of contents</h2>

- [models](#models)
- [Equals (type alias)](#equals-type-alias)
- [MergeLeft (type alias)](#mergeleft-type-alias)
- [MergeRight (type alias)](#mergeright-type-alias)
- [types](#types)
- [ExcludeTag (type alias)](#excludetag-type-alias)
- [ExtractTag (type alias)](#extracttag-type-alias)
- [Simplify (type alias)](#simplify-type-alias)
- [Tags (type alias)](#tags-type-alias)
- [UnionToIntersection (type alias)](#uniontointersection-type-alias)

---

# models

## Equals (type alias)

Determines if two types are equal.

**Signature**

```ts
export type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false
```
**Example**
```ts
import * as Types from '@effect/data/Types'

type Res1 = Types.Equals<{ a: number }, { a: number }> // true
type Res2 = Types.Equals<{ a: number }, { b: number }> // false
```
Added in v1.0.0
## MergeLeft (type alias)
Merges two object where the keys of the left object take precedence in the case of a conflict.
**Signature**
```ts
export type MergeLeft<K, H> = Simplify<{
[k in keyof K | keyof H]: k extends keyof K ? K[k] : k extends keyof H ? H[k] : never
}>
```
**Example**
```ts
import * as Types from '@effect/data/Types'
type MergeLeft = Types.MergeLeft<{ a: number; b: number }, { a: string }> // { a: number; b: number; }
```
Added in v1.0.0
## MergeRight (type alias)
Merges two object where the keys of the right object take precedence in the case of a conflict.
**Signature**
```ts
export type MergeRight<K, H> = Simplify<{
[k in keyof K | keyof H]: k extends keyof H ? H[k] : k extends keyof K ? K[k] : never
}>
```
**Example**
```ts
import * as Types from '@effect/data/Types'
type MergeRight = Types.MergeRight<{ a: number; b: number }, { a: string }> // { a: string; b: number; }
```
Added in v1.0.0
# types
## ExcludeTag (type alias)
Excludes the tagged object from the type.
**Signature**
```ts
export type ExcludeTag<E, K extends Tags<E>> = Exclude<E, { _tag: K }>
```
**Example**
```ts
import * as Types from '@effect/data/Types'

type Res = Types.ExcludeTag<string | { _tag: 'a' } | { _tag: 'b' }, 'a'> // string | { _tag: "b" }
```
Added in v1.0.0
## ExtractTag (type alias)
Extracts the type of the given tag.
**Signature**
```ts
export type ExtractTag<E, K extends Tags<E>> = Extract<E, { _tag: K }>
```
**Example**
```ts
import * as Types from '@effect/data/Types'

type Res = Types.ExtractTag<{ _tag: 'a'; a: number } | { _tag: 'b'; b: number }, 'b'> // { _tag: "b", b: number }
```
Added in v1.0.0
## Simplify (type alias)
Simplifies the type signature of a type.
**Signature**
```ts
export type Simplify<A> = {
[K in keyof A]: A[K]
} extends infer B
? B
: never
```
**Example**
```ts
import * as Types from '@effect/data/Types'

type Res = Types.Simplify<{ a: number } & { b: number }> // { a: number; b: number; }
```
Added in v1.0.0
## Tags (type alias)
Returns the tags in a type.
**Signature**
```ts
export type Tags<E> = E extends { _tag: string } ? E['_tag'] : never
```
**Example**
```ts
import * as Types from '@effect/data/Types'

type Res = Types.Tags<string | { _tag: 'a' } | { _tag: 'b' }> // "a" | "b"
```
Added in v1.0.0
## UnionToIntersection (type alias)
A utility type that transforms a union type `T` into an intersection type.
**Signature**
```ts
export type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never
```
Added in v1.0.0
28 changes: 28 additions & 0 deletions dtslint/Types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as Types from '@effect/data/Types'

// $ExpectType { a: string; } & { b: number; }
type UnionToIntersection = Types.UnionToIntersection<{ a: string } | { b: number }>

// $ExpectType "a" | "b"
type Tags = Types.Tags<string | { _tag: "a" } | { _tag: "b" }> & unknown

// $ExpectType string | { _tag: "b"; }
type ExcludeTag = Types.ExcludeTag<string | { _tag: "a" } | { _tag: "b" }, "a"> & unknown

// $ExpectType { _tag: "b"; b: number; }
type ExtractTag = Types.ExtractTag<string | { _tag: "a", a: number } | { _tag: "b", b: number }, "b"> & unknown

// $ExpectType { a: number; b: number; }
type Simplify = Types.Simplify<object & { a: number } & { b: number }>

// $ExpectType true
type Equals1 = Types.Equals<{ a: number }, { a: number }>

// $ExpectType false
type Equals2 = Types.Equals<{ a: number }, { b: number }>

// $ExpectType { a: number; b: number; }
type MergeLeft = Types.MergeLeft<{ a: number, b: number; }, { a: string }>

// $ExpectType { a: string; b: number; }
type MergeRight = Types.MergeRight<{ a: number, b: number; }, { a: string }>
16 changes: 4 additions & 12 deletions src/Brand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { identity } from "@effect/data/Function"
import * as Option from "@effect/data/Option"
import type { Predicate, Refinement } from "@effect/data/Predicate"
import * as ReadonlyArray from "@effect/data/ReadonlyArray"
import type * as Types from "@effect/data/Types"

/**
* @since 1.0.0
Expand Down Expand Up @@ -131,7 +132,7 @@ export declare namespace Brand {
* @since 1.0.0
* @category models
*/
export type Brands<P> = P extends Brand<any> ? Brand.UnionToIntersection<
export type Brands<P> = P extends Brand<any> ? Types.UnionToIntersection<
{
[k in keyof P[BrandTypeId]]: k extends string | symbol ? Brand<k>
: never
Expand All @@ -155,15 +156,6 @@ export declare namespace Brand {
: Brands[B]
: "ERROR: All brands should have the same base type"
}

/**
* A utility type that transforms a union type `T` into an intersection type.
*
* @since 1.0.0
* @category models
*/
export type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R
: never
}

/**
Expand Down Expand Up @@ -305,12 +297,12 @@ export const nominal: <A extends Brand<any>>() => Brand.Constructor<A> = <A exte
export const all: <Brands extends readonly [Brand.Constructor<any>, ...Array<Brand.Constructor<any>>]>(
...brands: Brand.EnsureCommonBase<Brands>
) => Brand.Constructor<
Brand.UnionToIntersection<{ [B in keyof Brands]: Brand.FromConstructor<Brands[B]> }[number]> extends
Types.UnionToIntersection<{ [B in keyof Brands]: Brand.FromConstructor<Brands[B]> }[number]> extends
infer X extends Brand<any> ? X : Brand<any>
> = <
Brands extends readonly [Brand.Constructor<any>, ...Array<Brand.Constructor<any>>]
>(...brands: Brand.EnsureCommonBase<Brands>): Brand.Constructor<
Brand.UnionToIntersection<
Types.UnionToIntersection<
{
[B in keyof Brands]: Brand.FromConstructor<Brands[B]>
}[number]
Expand Down
18 changes: 4 additions & 14 deletions src/Data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import * as Equal from "@effect/data/Equal"
import * as Hash from "@effect/data/Hash"
import type * as Types from "@effect/data/Types"

/**
* @category models
Expand Down Expand Up @@ -130,15 +131,6 @@ export const tagged = <A extends Case & { _tag: string }>(
// @ts-expect-error
(args) => args === undefined ? struct({ _tag: tag }) : struct({ ...args, _tag: tag })

/**
* @since 1.0.0
* @category models
*/
export type IsEqualTo<X, Y> = (<T>() => T extends X ? 1 : 2) extends <
T
>() => T extends Y ? 1 : 2 ? true
: false

/**
* Provides a Tagged constructor for a Case Class.
*
Expand All @@ -148,7 +140,7 @@ export type IsEqualTo<X, Y> = (<T>() => T extends X ? 1 : 2) extends <
export const TaggedClass = <Key extends string>(
tag: Key
): new<A extends Record<string, any>>(
args: IsEqualTo<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
args: Types.Equals<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
) => Data<A & { _tag: Key }> => {
class Base extends (Class as any) {
readonly _tag = tag
Expand All @@ -163,7 +155,7 @@ export const TaggedClass = <Key extends string>(
* @category constructors
*/
export const Class: new<A extends Record<string, any>>(
args: IsEqualTo<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
args: Types.Equals<Omit<A, keyof Equal.Equal>, {}> extends true ? void : Omit<A, keyof Equal.Equal>
) => Data<A> = (() => {
class Base<A> {
constructor(args: Omit<A, keyof Equal.Equal>) {
Expand Down Expand Up @@ -191,8 +183,6 @@ export const Class: new<A extends Record<string, any>>(
return Base as any
})()

type Simplify<A> = { [K in keyof A]: A[K] } & {}

/**
* Create a tagged enum data type, which is a union of `Data` structs.
*
Expand Down Expand Up @@ -223,7 +213,7 @@ type Simplify<A> = { [K in keyof A]: A[K] } & {}
*/
export type TaggedEnum<A extends Record<string, Record<string, any>>> = {
readonly [Tag in keyof A]: Data<
Simplify<Readonly<A[Tag]> & { readonly _tag: Tag }>
Readonly<Types.Simplify<A[Tag] & { _tag: Tag }>>
>
}[keyof A]

Expand Down

0 comments on commit 41ddfb7

Please sign in to comment.