├── .github └── workflows │ └── main.yml ├── .gitignore ├── .npmignore ├── CODE-OF-CONDUCT.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── Array.ts ├── Control │ ├── Control.ts │ └── State.ts ├── Function.ts ├── Object.ts ├── Operator │ ├── Eq.ts │ └── Intersection.ts ├── Primitive │ ├── Assert.ts │ ├── HKT.ts │ ├── Newtype.ts │ ├── PhantomTypeParameter.ts │ ├── Stuck.ts │ └── TType.ts ├── Promoted │ ├── TArray.ts │ ├── TBoolean.ts │ ├── TNumber.ts │ ├── TObject.ts │ └── TString.ts └── index.ts └── tsconfig.json /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | 7 | steps: 8 | - name: Begin CI... 9 | uses: actions/checkout@v2 10 | 11 | - name: Use Node 12 12 | uses: actions/setup-node@v1 13 | with: 14 | node-version: 12.x 15 | 16 | - name: Use cached node_modules 17 | uses: actions/cache@v1 18 | with: 19 | path: node_modules 20 | key: nodeModules-${{ hashFiles('**/yarn.lock') }} 21 | restore-keys: | 22 | nodeModules- 23 | 24 | - name: Install dependencies 25 | run: yarn install --frozen-lockfile 26 | env: 27 | CI: true 28 | 29 | - name: Build 30 | run: yarn build 31 | env: 32 | CI: true 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | dist 5 | .idea -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .DS_Store 3 | node_modules 4 | .idea 5 | src 6 | docs 7 | .github 8 | CODE-OF-CONDUCT.md 9 | tsconfig.json 10 | .gitignore -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # CODE-OF-CONDUCT 2 | 3 | ## Don'ts 4 | 5 | Whatever you can't tell your family, friends or others that you did it. 6 | 7 | ## Do's 8 | 9 | Anything except Don'ts -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 ENvironmentSet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # welltyped 2 | 3 | Collection of Dependently-typed stuff 4 | 5 | ## Documentation is WIP 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0-alpha.6", 3 | "license": "MIT", 4 | "main": "dist/index.js", 5 | "module": "dist/welltyped.esm.js", 6 | "typings": "dist/index.d.ts", 7 | "files": [ 8 | "dist", 9 | "src" 10 | ], 11 | "scripts": { 12 | "build": "tsdx build" 13 | }, 14 | "name": "welltyped", 15 | "author": "ENvironmentSet (https://github.com/ENvironmentSet)", 16 | "description": "Collection of Dependently-typed stuff", 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/ENvironmentSet/welltyped.git" 20 | }, 21 | "bugs": { 22 | "url": "https://github.com/ENvironmentSet/welltyped/issues" 23 | }, 24 | "homepage": "https://github.com/ENvironmentSet/welltyped#readme", 25 | "devDependencies": { 26 | "husky": "^4.2.5", 27 | "tsdx": "^0.13.3", 28 | "tslib": "^2.3.1", 29 | "typescript": "^4.5.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Array.ts: -------------------------------------------------------------------------------- 1 | import { TArray, Cons, Concat } from './Promoted/TArray'; 2 | import { TType } from './Primitive/TType'; 3 | 4 | export function cons(x: type, xs: tarray): Cons { 5 | return [x, ...xs]; 6 | } 7 | 8 | export function head([x]: Cons): type { 9 | return x; 10 | } 11 | 12 | export function tail([_, ...xs]: Cons): tarray { 13 | return xs; 14 | } 15 | 16 | export function concat(xs: xs, ys: ys): Concat { 17 | return [...xs, ...ys]; 18 | } 19 | -------------------------------------------------------------------------------- /src/Control/Control.ts: -------------------------------------------------------------------------------- 1 | import { HKT } from '../Primitive/HKT'; 2 | import { TType } from '../Primitive/TType'; 3 | import { TBoolean } from '../Promoted/TBoolean' 4 | 5 | export type If = condition extends true ? then : orElse; 6 | export interface If_ extends HKT { 7 | params: [TBoolean, TType, TType]; 8 | condition: this['params'][0]; 9 | then: this['params'][1]; 10 | orElse: this['params'][2]; 11 | result: If; 12 | } 13 | -------------------------------------------------------------------------------- /src/Control/State.ts: -------------------------------------------------------------------------------- 1 | import { PhantomTypeParameter } from '../Primitive/PhantomTypeParameter'; 2 | import { TType } from '../Primitive/TType'; 3 | import { Apply, HKT } from '../Primitive/HKT'; 4 | 5 | type Context = PhantomTypeParameter<'welltyped/state/context', context>; 6 | type Shadow = PhantomTypeParameter<'welltyped/state/phantom', shadow>; 7 | type PickContext = state extends Context ? context : never; 8 | type PickShadow = shadow extends Shadow ? shadow : never; 9 | 10 | export interface Return extends HKT { //@TODO: Make State strictly typed via kind polymorphism. 11 | params: [TType]; 12 | context: this['params'][0]; 13 | result: a & Context & Shadow; 14 | } 15 | 16 | export interface Bind extends HKT { 17 | params: [TType]; 18 | context: this['params'][0]; 19 | result: Apply, PickContext]> 20 | } 21 | 22 | export type Exec = Apply; 23 | -------------------------------------------------------------------------------- /src/Function.ts: -------------------------------------------------------------------------------- 1 | import { Head, Length, Tail, TArray } from './Promoted/TArray'; 2 | import { Eq } from './Promoted/Eq'; 3 | import { Assert } from './Primitive/Assert'; 4 | 5 | export type TFunction = (...args: never) => unknown; 6 | type ConstraintVariadicFunction 7 | = Eq>, number> extends true ? [never] : never; 8 | 9 | export type Curried 10 | = Length> extends 0 ? 11 | ReturnType 12 | : (x: Head>) => Curried<(...args: Assert>, TArray>) => ReturnType>; 13 | //@FIXME(Assert): IDK Why typescript can't catch that result of type well if there is variadic element with conditional type. 14 | 15 | function setFunctionLength(f: f, length: number): f { 16 | return Object.defineProperty(f, 'length', { value: length }); 17 | } 18 | 19 | //@FIXME: Is there any nature way not to use @ts-ignore? 20 | export function curry 21 | > 22 | (f: f): Length> extends 0 ? f : Curried { 23 | if (f.length < 2) return f as Length> extends 0 ? f : Curried; 24 | //@ts-ignore 25 | else return x => curry(setFunctionLength((...args) => f(x, ...args), f.length - 1)); 26 | } 27 | -------------------------------------------------------------------------------- /src/Object.ts: -------------------------------------------------------------------------------- 1 | import { TObject, Set, Get } from './Promoted/TObject'; 2 | import { TString } from './Promoted/TString'; 3 | import { TType } from './Primitive/TType'; 4 | 5 | export function get(o: o, k: k): Get { 6 | return o[k]; 7 | } 8 | 9 | export function set(o: o, k: k, v: v): Set { 10 | return { ...o, [k]: v } as Set; 11 | } 12 | -------------------------------------------------------------------------------- /src/Operator/Eq.ts: -------------------------------------------------------------------------------- 1 | import { HKT } from '../Primitive/HKT'; 2 | import { TType } from '../Primitive/TType'; 3 | 4 | export type Eq = 5 | (() => T extends a ? never : never) extends (() => T extends b ? never : never) ? 6 | true : false; 7 | export interface Eq_ extends HKT { 8 | params: [TType, TType]; 9 | a: this['params'][0]; 10 | b: this['params'][1]; 11 | result: Eq; 12 | } 13 | -------------------------------------------------------------------------------- /src/Operator/Intersection.ts: -------------------------------------------------------------------------------- 1 | import { HKT } from '../Primitive/HKT'; 2 | import { TType } from '../Primitive/TType'; 3 | 4 | export type Intersection = a & b; 5 | export interface Intersection_ extends HKT { 6 | params: [TType, TType] 7 | a: this['params'][0]; 8 | b: this['params'][1]; 9 | result: Intersection; 10 | } 11 | -------------------------------------------------------------------------------- /src/Primitive/Assert.ts: -------------------------------------------------------------------------------- 1 | import { Stuck } from './Stuck'; 2 | 3 | export type Assert = type extends ttype ? type : Stuck; 4 | -------------------------------------------------------------------------------- /src/Primitive/HKT.ts: -------------------------------------------------------------------------------- 1 | import { TType } from './TType'; 2 | import { Stuck } from './Stuck'; 3 | import { Eq } from '../Operator/Eq'; 4 | 5 | export interface HKT { 6 | params: TType[]; 7 | result: TType; 8 | } 9 | 10 | export type Apply 11 | = Eq<(f & { params: tParams })['result'], Stuck> extends true ? fallback : (f & { params: tParams })['result']; 12 | -------------------------------------------------------------------------------- /src/Primitive/Newtype.ts: -------------------------------------------------------------------------------- 1 | import { PhantomTypeParameter } from './PhantomTypeParameter'; 2 | import { Stuck } from './Stuck'; 3 | 4 | export type Newtype = type & PhantomTypeParameter; -------------------------------------------------------------------------------- /src/Primitive/PhantomTypeParameter.ts: -------------------------------------------------------------------------------- 1 | export abstract class PhantomTypeParameter { 2 | protected readonly abstract _: { 3 | readonly [NameP in Identifier]: (_: InstantiatedType) => InstantiatedType; 4 | }; 5 | } -------------------------------------------------------------------------------- /src/Primitive/Stuck.ts: -------------------------------------------------------------------------------- 1 | export type Stuck = never; -------------------------------------------------------------------------------- /src/Primitive/TType.ts: -------------------------------------------------------------------------------- 1 | export type TType = unknown; 2 | -------------------------------------------------------------------------------- /src/Promoted/TArray.ts: -------------------------------------------------------------------------------- 1 | import { Stuck } from '../Primitive/Stuck'; 2 | import { TType } from '../Primitive/TType'; 3 | import { HKT, Apply } from '../Primitive/HKT'; 4 | import { If } from './Control'; 5 | import { TNumber } from './TNumber'; 6 | 7 | export type TArray = Array; 8 | export type Empty = []; 9 | 10 | export type MakeTArray 11 | = Length extends length ? result : MakeTArray; 12 | 13 | export type IsEmpty = Length extends 0 ? true : false; 14 | export interface IsEmpty_ extends HKT { 15 | params: [TArray]; 16 | l: this['params'][0]; 17 | result: IsEmpty; 18 | } 19 | 20 | export type Head = If, Stuck, l[0]>; 21 | export interface Head_ extends HKT { 22 | params: [TArray]; 23 | l: this['params'][0]; 24 | result: Head; 25 | } 26 | 27 | export type Tail = l extends [unknown, ...infer tail] ? tail : Stuck 28 | export interface Tail_ extends HKT { 29 | params: [TArray]; 30 | l: this['params'][0]; 31 | result: Tail; 32 | } 33 | 34 | export type Init = l extends [...infer init, unknown] ? init : Stuck; 35 | export interface Init_ extends HKT { 36 | params: [TArray]; 37 | l: this['params'][0]; 38 | result: Init; 39 | } 40 | 41 | export type Last = l extends [] ? Stuck : Length extends 1 ? Head : Last>; 42 | export interface Last_ extends HKT { 43 | params: [TArray]; 44 | l: this['params'][0]; 45 | result: Last; 46 | } 47 | 48 | //@FIXME: Can't return l['length'] directly, seems bug of TS 4.1 49 | export type Length = l['length'] extends infer N ? N extends TNumber ? N : Stuck : Stuck; 50 | export interface Length_ extends HKT { 51 | params: [TArray]; 52 | l: this['params'][0]; 53 | result: Length; 54 | } 55 | 56 | export type Cons = [car, ...cdr]; 57 | export interface Cons_ extends HKT { 58 | params: [TType, TArray]; 59 | car: this['params'][0]; 60 | cdr: this['params'][1]; 61 | result: Cons; 62 | } 63 | 64 | //@FIXME: TS Bug: Using recursive type with 'If' sometime goes wrong. 65 | export type Map 66 | = IsEmpty extends true ? Stuck : Cons]>, Map>>; 67 | export interface Map_ extends HKT { 68 | params: [HKT, TArray]; 69 | f: this['params'][0]; 70 | l: this['params'][1]; 71 | result: Map; 72 | } 73 | 74 | export type Concat = [...xs, ...ys]; 75 | export interface Concat_ extends HKT { 76 | params: [TArray, TArray]; 77 | xs: this['params'][0]; 78 | ys: this['params'][1]; 79 | result: Concat; 80 | } 81 | -------------------------------------------------------------------------------- /src/Promoted/TBoolean.ts: -------------------------------------------------------------------------------- 1 | import { HKT } from '../Primitive/HKT'; 2 | 3 | export type TBoolean = boolean; 4 | 5 | export type Not = x extends true ? false : true; 6 | export interface Not_ extends HKT { 7 | params: [TBoolean]; 8 | x: this['params'][0] 9 | result: Not; 10 | } 11 | -------------------------------------------------------------------------------- /src/Promoted/TNumber.ts: -------------------------------------------------------------------------------- 1 | import { Stuck } from '../Primitive/Stuck'; 2 | import { HKT } from '../Primitive/HKT'; 3 | import {Length, MakeTArray, Tail, TArray} from './TArray'; 4 | 5 | export type TNumber = number; 6 | 7 | export type Inc = Add; 8 | export interface Inc_ extends HKT { 9 | params: [TNumber]; 10 | x: this['params'][0]; 11 | result: Inc; 12 | } 13 | 14 | export type Add = Length<[...MakeTArray, ...MakeTArray]>; 15 | export interface Add_ extends HKT { 16 | params: [TNumber, TNumber]; 17 | x: this['params'][0]; 18 | y: this['params'][1]; 19 | result: Add; 20 | } 21 | 22 | //@FIXME: Can't use Length to L directly, this might be bug of TS 4.1 23 | export type Dec 24 | = Tail> extends infer L ? L extends TArray ? Length : Stuck : Stuck; 25 | export interface Dec_ extends HKT { 26 | params: [TNumber]; 27 | x: this['params'][0]; 28 | result: Dec; 29 | } 30 | 31 | export type Sub = x extends 0 ? 0 : Sub, Dec>; 32 | export interface Sub_ extends HKT { 33 | params: [TNumber, TNumber]; 34 | x: this['params'][0]; 35 | y: this['params'][1]; 36 | result: Sub; 37 | } 38 | 39 | export type Mul = x extends 0 ? 0 : y extends 0 ? 0 : Add>, x>; 40 | export interface Mul_ extends HKT { 41 | params: [TNumber, TNumber]; 42 | x: this['params'][0]; 43 | y: this['params'][1]; 44 | result: Mul; 45 | } 46 | -------------------------------------------------------------------------------- /src/Promoted/TObject.ts: -------------------------------------------------------------------------------- 1 | import { TString } from './TString'; 2 | import { TType } from '../Primitive/TType'; 3 | import { HKT } from '../Primitive/HKT'; 4 | import { Stuck } from '../Primitive/Stuck'; 5 | 6 | //@TODO Make type families first class. 7 | 8 | export type TObject = object; 9 | 10 | export type Get = o[k]; 11 | export interface Get_ extends HKT{ 12 | params: [TObject, TString]; 13 | o: this['params'][0]; 14 | k: this['params'][1]; 15 | result: this['k'] extends keyof this['o'] ? Get : Stuck; 16 | } 17 | 18 | export type Set 19 | = Pick> & Record; 20 | export interface Set_ extends HKT{ 21 | params: [TObject, TString, TType]; 22 | o: this['params'][0]; 23 | k: this['params'][1]; 24 | v: this['params'][2]; 25 | result: Set; 26 | } 27 | -------------------------------------------------------------------------------- /src/Promoted/TString.ts: -------------------------------------------------------------------------------- 1 | export type TString = string; 2 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Array'; 2 | export * from './Function'; 3 | export * from './Object'; 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src", "types"], 3 | "compilerOptions": { 4 | "module": "esnext", 5 | "lib": ["esnext"], 6 | "importHelpers": true, 7 | "declaration": true, 8 | "sourceMap": true, 9 | "rootDir": "./src", 10 | "strict": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": false, 13 | "noImplicitReturns": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "moduleResolution": "node" 16 | } 17 | } 18 | --------------------------------------------------------------------------------