├── dtslint ├── ts3.5 │ ├── index.d.ts │ ├── tsconfig.json │ ├── tslint.json │ └── index.ts └── index.d.ts ├── .travis.yml ├── .gitignore ├── .vscode └── settings.json ├── .prettierrc ├── docs ├── index.md ├── modules │ ├── index.md │ └── index.ts.md └── _config.yml ├── tslint.json ├── README.md ├── examples ├── withProps.tsx ├── withDefaults.tsx └── tsconfig.json ├── tsconfig.json ├── LICENSE ├── package.json ├── CHANGELOG.md └── src └── index.ts /dtslint/ts3.5/index.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dtslint/index.d.ts: -------------------------------------------------------------------------------- 1 | // TypeScript Version: 3.5 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules 3 | lib 4 | dev 5 | /.idea/ 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "./node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "printWidth": 120 5 | } 6 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | nav_order: 1 4 | --- 5 | 6 | # Type level programming in TypeScript 7 | -------------------------------------------------------------------------------- /docs/modules/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Modules 3 | has_children: true 4 | permalink: /docs/modules 5 | nav_order: 2 6 | --- 7 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | remote_theme: pmarsceill/just-the-docs 2 | 3 | # Enable or disable the site search 4 | search_enabled: true 5 | 6 | # Aux links for the upper right navigation 7 | aux_links: 8 | 'typelevel-ts on GitHub': 9 | - '//github.com/gcanti/typelevel-ts' 10 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint-config-standard", 3 | "rules": { 4 | "space-before-function-paren": false, 5 | "no-use-before-declare": false, 6 | "variable-name": false, 7 | "quotemark": [true, "single", "jsx-double"], 8 | "ter-indent": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeScript compatibility 2 | 3 | | `typelevel-ts` version | required `typescript` version | 4 | | ---------------------- | ----------------------------- | 5 | | 0.4.x | 3.5+ | 6 | | 0.3.x | 2.9.1+ | 7 | 8 | # Documentation 9 | 10 | - [API Reference](https://gcanti.github.io/typelevel-ts) 11 | -------------------------------------------------------------------------------- /examples/withProps.tsx: -------------------------------------------------------------------------------- 1 | import { Omit } from 'typelevel-ts' 2 | import * as React from 'react' 3 | 4 | function withProps(C: React.ComponentType

, values: D): React.SFC> { 5 | return props => 6 | } 7 | 8 | class Foo extends React.Component<{ bar: string; baz: number }> {} 9 | const FilledFoo = withProps(Foo, { baz: 1 }) 10 | const x = // ok 11 | -------------------------------------------------------------------------------- /dtslint/ts3.5/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "strict": true, 5 | "noImplicitAny": true, 6 | "noImplicitThis": true, 7 | "strictNullChecks": true, 8 | "strictFunctionTypes": true, 9 | "noImplicitReturns": false, 10 | "noUnusedLocals": false, 11 | "noUnusedParameters": false, 12 | "noFallthroughCasesInSwitch": true, 13 | "target": "es5", 14 | "lib": ["es2015"] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/withDefaults.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | import { Diff } from 'typelevel-ts' 3 | 4 | function withDefaults(C: React.ComponentType, defaults: D): React.SFC> { 5 | return props => 6 | } 7 | 8 | class Foo extends React.Component<{ bar: string; baz: number }> {} 9 | const DefaultedFoo = withDefaults(Foo, { baz: 1 }) 10 | const x = // ok 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./lib", 4 | "sourceMap": true, 5 | "declaration": true, 6 | "module": "commonjs", 7 | "strict": true, 8 | "noImplicitReturns": false, 9 | "noUnusedLocals": true, 10 | "noUnusedParameters": false, 11 | "noFallthroughCasesInSwitch": true, 12 | "noEmitOnError": false, 13 | "allowJs": false, 14 | "target": "es5", 15 | "moduleResolution": "node", 16 | "forceConsistentCasingInFileNames": true, 17 | "lib": ["es6", "dom"] 18 | }, 19 | "include": ["./src/**/*"] 20 | } 21 | -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "jsx": "react", 5 | "module": "commonjs", 6 | "noImplicitAny": true, 7 | "noImplicitReturns": false, 8 | "noImplicitThis": false, 9 | "noUnusedLocals": false, 10 | "noUnusedParameters": false, 11 | "noFallthroughCasesInSwitch": true, 12 | "noEmitOnError": false, 13 | "allowJs": false, 14 | "strictNullChecks": true, 15 | "target": "es5", 16 | "moduleResolution": "node", 17 | "forceConsistentCasingInFileNames": true, 18 | "lib": [ 19 | "es6", 20 | "dom" 21 | ], 22 | "baseUrl": ".", 23 | "paths": { 24 | "typelevel-ts/lib/*": [ 25 | "../src/*" 26 | ], 27 | "typelevel-ts": [ 28 | "../src/index" 29 | ] 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /dtslint/ts3.5/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "dtslint/dtslint.json", 3 | "rules": { 4 | "semicolon": false, 5 | "array-type": false, 6 | "no-unnecessary-generics": false, 7 | "member-access": false, 8 | "no-empty-interface": false, 9 | "no-arg": false, 10 | "no-object-literal-type-assertion": false, 11 | "no-unnecessary-class": false, 12 | "radix": false, 13 | "no-angle-bracket-type-assertion": false, 14 | "object-literal-shorthand": false, 15 | "prefer-object-spread": false, 16 | "whitespace": false, 17 | "use-default-type-parameter": false, 18 | "no-relative-import-in-test": false, 19 | "no-null-undefined-union": false, 20 | "invalid-void": false, 21 | "no-var-keyword": false, 22 | "no-duplicate-variable": false, 23 | "interface-over-type-literal": false, 24 | "unnecessary-else": false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Giulio Canti 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. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typelevel-ts", 3 | "version": "0.4.0", 4 | "description": "Type level programming in TypeScript", 5 | "files": [ 6 | "lib" 7 | ], 8 | "main": "lib/index.js", 9 | "typings": "lib/index.d.ts", 10 | "scripts": { 11 | "lint": "tslint src/**/*.ts", 12 | "prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --list-different \"{src,typings-checker}/**/*.ts\"", 13 | "fix-prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --write \"{src,typings-checker}/**/*.ts\"", 14 | "test": "npm run prettier && npm run lint && npm run dtslint && npm run docs", 15 | "clean": "rm -rf lib/*", 16 | "build": "npm run clean && tsc", 17 | "dtslint": "dtslint dtslint", 18 | "docs": "docs-ts" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/gcanti/typelevel-ts.git" 23 | }, 24 | "author": "Giulio Canti ", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/gcanti/typelevel-ts/issues" 28 | }, 29 | "homepage": "https://github.com/gcanti/typelevel-ts", 30 | "dependencies": {}, 31 | "devDependencies": { 32 | "@types/react": "^16.3.17", 33 | "docs-ts": "^0.3.0", 34 | "dtslint": "github:gcanti/dtslint", 35 | "prettier": "^1.19.1", 36 | "react": "^16.4.0", 37 | "tslint": "4.4.2", 38 | "tslint-config-standard": "4.0.0", 39 | "typescript": "^3.7.4" 40 | }, 41 | "tags": [], 42 | "keywords": [] 43 | } 44 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | > **Tags:** 4 | > 5 | > - [New Feature] 6 | > - [Bug Fix] 7 | > - [Breaking Change] 8 | > - [Documentation] 9 | > - [Internal] 10 | > - [Polish] 11 | > - [Experimental] 12 | 13 | **Note**: Gaps between patch versions are faulty/broken releases. **Note**: A feature tagged as Experimental is in a 14 | high state of flux, you're at risk of it changing without notice. 15 | 16 | # 0.4.0 17 | 18 | - **Breaking Change** 19 | - remove `Omit` type, use built-in instead (@gcanti) 20 | - **Bug Fix** 21 | - rewrite `Overwrite` definition using built-in `Omit`, fix #43 (@looading) 22 | 23 | # 0.3.5 24 | 25 | - **Polish** 26 | - better `Equals`, closes #39 (thanks @aleclarson) 27 | 28 | # 0.3.4 29 | 30 | - **Polish** 31 | - handle empty object and primitives in `RequiredKeys` and `OptionalKeys` (@ajafff) 32 | 33 | # 0.3.3 34 | 35 | - **New Feature** 36 | - add `RequiredKeys` and `OptionalKeys` types, #33 (@saitonakamura) 37 | - **Bug Fix** 38 | - KeysOfType now handles optional keys, fix #34 (@gcanti) 39 | 40 | # 0.3.2 41 | 42 | - **Bug Fix** 43 | - use `never` instead of `undefined` in `Exact` definition, fix #31 (thanks @leighman) 44 | 45 | # 0.3.1 46 | 47 | - **New Feature** 48 | - add `KeysOfType` (@mattiamanzati) 49 | - add `TaggedUnionMember` (@gcanti) 50 | 51 | # 0.3.0 52 | 53 | - **Breaking Change** 54 | - upgrade to `typescript@2.9.x` (@gcanti) 55 | 56 | # 0.2.4 57 | 58 | - **Internal** 59 | - support `typescript@2.8.3` (@gcanti) 60 | 61 | # 0.2.3 62 | 63 | - **New Feature** 64 | - add `HListConcat`, closes #17 (@tvald) 65 | 66 | # 0.2.2 67 | 68 | - **New Feature** 69 | - add `Required`, `Purify`, `NonNullable`, closes #15 (@gcanti) 70 | 71 | # 0.2.1 72 | 73 | - **New Feature** 74 | - add `ObjectOptional`, closes #13 (@thepheer) 75 | 76 | # 0.2.0 77 | 78 | - **Breaking Change** 79 | - complete refactoring 80 | - upgrade to TypeScript 2.5.2 (@gcanti) 81 | 82 | # 0.1.3 83 | 84 | - **New Feature** 85 | - `NumberToNat` 86 | - `NatToNumber` 87 | - hlists 88 | - tuples 89 | - convert tuples to / from hlists (`TupleToTHList`, `THListToTuple`) 90 | 91 | # 0.1.2 92 | 93 | - **Bug Fix** 94 | - remove `ObjectExact` (@gcanti) 95 | 96 | # 0.1.1 97 | 98 | - **New Feature** 99 | - `PickExact` (@gcanti) 100 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.3.0 3 | */ 4 | 5 | /** 6 | * @since 0.3.0 7 | */ 8 | export type Compact = { [K in keyof A]: A[K] } 9 | 10 | /** 11 | * Returns the string literal 'T' if `A` and `B` are equal types, 'F' otherwise 12 | * 13 | * @example 14 | * import { Equals } from 'typelevel-ts' 15 | * 16 | * export type Result1 = Equals // "T" 17 | * export type Result2 = Equals // "F" 18 | * 19 | * @since 0.3.0 20 | */ 21 | export type Equals = (() => C extends Compact ? 'T' : 'F') extends () => C extends Compact ? 'T' : 'F' 22 | ? 'T' 23 | : 'F' 24 | 25 | /** 26 | * @example 27 | * import { Overwrite } from 'typelevel-ts' 28 | * 29 | * export type Result = Overwrite<{ a: string; b: number }, { b: boolean }> // { a: string; b: boolean } 30 | * 31 | * @since 0.3.0 32 | */ 33 | export type Overwrite = Compact & B> 34 | 35 | /** 36 | * @example 37 | * import { Diff } from 'typelevel-ts' 38 | * 39 | * export type Result = Diff<{ a: string; b: number }, 'b'> // { a: string; b?: number } 40 | * 41 | * @since 0.3.0 42 | */ 43 | export type Diff = Compact< 44 | { [K in Exclude]: A[K] } & { [K in OK]?: A[K] } 45 | > 46 | 47 | /** 48 | * Picks only the keys of a certain type 49 | * 50 | * @example 51 | * import { KeysOfType } from 'typelevel-ts' 52 | * 53 | * export type Result = KeysOfType<{a: string, b: string | boolean, c: boolean, d: string}, string> // "a" | "d" 54 | * 55 | * @since 0.3.0 56 | */ 57 | export type KeysOfType = { [K in keyof A]-?: A[K] extends B ? K : never }[keyof A] 58 | 59 | /** 60 | * Encodes the constraint that a given object `A` does not contain specific keys `K` 61 | * 62 | * @example 63 | * import { RowLacks } from 'typelevel-ts' 64 | * 65 | * // function f(x: RowLacks<{ a: string; b: number }, 'a' | 'b'>): void {} 66 | * // $ExpectError 67 | * // f({ a: 'a', b: 1 }) 68 | * function g(x: RowLacks<{ a: string; b: number }, 'c'>): void {} 69 | * g({ a: 'a', b: 1 }) // ok 70 | * 71 | * @since 0.3.0 72 | */ 73 | export type RowLacks = A & Record, never> 74 | 75 | /** 76 | * @example 77 | * import { Exact } from 'typelevel-ts' 78 | * 79 | * function f>(a: T): void {} 80 | * f({ a: 'a' }) 81 | * // $ExpectError 82 | * // f({ a: 'a', b: 1 }) 83 | * 84 | * @since 0.3.0 85 | */ 86 | export type Exact = A & Record, never> 87 | 88 | /** 89 | * @example 90 | * import { AnyTuple } from 'typelevel-ts' 91 | * 92 | * function f(x: T): T { 93 | * return x 94 | * } 95 | * const x: [number] = [1] 96 | * const y: [number, string] = [1, 'a'] 97 | * const z: [number, string, boolean] = [1, 'a', true] 98 | * f(x) 99 | * f(y) 100 | * f(z) 101 | * // $ExpectError 102 | * // f([1, 2, 3]) 103 | * 104 | * @since 0.3.0 105 | */ 106 | export type AnyTuple = Array & { '0': any } 107 | 108 | /** 109 | * @internal 110 | * @since 0.3.0 111 | */ 112 | export interface DeepReadonlyArray extends ReadonlyArray> {} 113 | 114 | /** 115 | * @internal 116 | * @since 0.3.0 117 | */ 118 | export type DeepReadonlyObject = { readonly [K in keyof A]: DeepReadonly } 119 | 120 | /** 121 | * @example 122 | * import { DeepReadonly } from 'typelevel-ts' 123 | * 124 | * interface Foo { 125 | * bar: { 126 | * baz: string 127 | * quux: Array<{ barbaz: number }> 128 | * } 129 | * } 130 | * 131 | * type ReadonlyFoo = DeepReadonly 132 | * export declare const x: ReadonlyFoo 133 | * // $ExpectError 134 | * // x.bar.quux[1].barbaz = 1 135 | * 136 | * @since 0.3.0 137 | */ 138 | export type DeepReadonly = A extends Array ? DeepReadonlyArray : DeepReadonlyObject 139 | 140 | /** 141 | * Extracts the type of a member of a tagged union 142 | * 143 | * @example 144 | * import { TaggedUnionMember } from 'typelevel-ts' 145 | * 146 | * type A = { tag: 'A'; a: string } 147 | * type B = { tag: 'B'; b: number } 148 | * type C = A | B 149 | * export type Result = TaggedUnionMember // A 150 | * 151 | * @since 0.3.0 152 | */ 153 | export type TaggedUnionMember = Extract< 154 | A, 155 | Record 156 | > 157 | 158 | /** 159 | * Extracts required keys as a literal type union 160 | * 161 | * @example 162 | * import { RequiredKeys } from 'typelevel-ts' 163 | * 164 | * type A = { a: string; b: number; x?: string; y?: number } 165 | * export type Result = RequiredKeys // "a" | "b" 166 | * 167 | * @since 0.3.0 168 | */ 169 | export type RequiredKeys = { [K in keyof T]: {} extends Pick ? never : K } extends { [_ in keyof T]: infer U } 170 | ? {} extends U 171 | ? never 172 | : U 173 | : never 174 | 175 | /** 176 | * Extracts optional keys as a literal type union 177 | * 178 | * @example 179 | * import { OptionalKeys } from 'typelevel-ts' 180 | * 181 | * type A = { a: string; b: number; x?: string; y?: number } 182 | * export type Result = OptionalKeys // "x" | "y" 183 | * 184 | * @since 0.3.0 185 | */ 186 | export type OptionalKeys = { [K in keyof T]: T extends Record ? never : K } extends { 187 | [_ in keyof T]: infer U 188 | } 189 | ? {} extends U 190 | ? never 191 | : U 192 | : never 193 | -------------------------------------------------------------------------------- /dtslint/ts3.5/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AnyTuple, 3 | Equals, 4 | Exact, 5 | Overwrite, 6 | Diff, 7 | RowLacks, 8 | DeepReadonly, 9 | KeysOfType, 10 | TaggedUnionMember, 11 | RequiredKeys, 12 | OptionalKeys 13 | } from '../../src' 14 | 15 | // 16 | // Equals 17 | // 18 | 19 | type Equals1 = Equals // $ExpectType "T" 20 | type Equals2 = Equals // $ExpectType "F" 21 | type Equals3 = Equals<'a' | 'b', 'a' | 'b'> // $ExpectType "T" 22 | type Equals4 = Equals<'a' | 'b', 'a' | 'c'> // $ExpectType "F" 23 | type Equals5 = Equals, Array> // $ExpectType "T" 24 | type Equals6 = Equals, Array> // $ExpectType "F" 25 | type Equals7 = Equals // $ExpectType "F" 26 | type Equals8 = Equals // $ExpectType "F" 27 | type Equals9 = Equals, Map> // $ExpectType "F" 28 | type Equals10 = Equals<{ a: string } & { b: number }, { a: string; b: number }> // $ExpectType "T" 29 | 30 | // 31 | // Omit 32 | // 33 | 34 | type Omit1 = Omit<{ a: string; b: number }, 'a'> // $ExpectType Pick<{ a: string; b: number; }, "b"> 35 | type Omit2 = Omit<{ a: string; b: number }, 'a' | 'b'> // $ExpectType Pick<{ a: string; b: number; }, never> 36 | type Omit3 = Omit<{ a: string; b: number }, 'a' | 'c'> // $ExpectType Pick<{ a: string; b: number; }, "b"> 37 | 38 | // 39 | // Overwrite 40 | // 41 | 42 | type Overwrite1 = Overwrite<{ a: string; b: number }, { b: boolean }> // $ExpectType Compact & { b: boolean; }> 43 | type Overwrite2 = Overwrite<{ a?: string; b: number }, { b: boolean }> // $ExpectType Compact & { b: boolean; }> 44 | type Overwrite3 = Overwrite<{ a: string }, { b: boolean }> // $ExpectType Compact & { b: boolean; }> 45 | type Overwrite4 = Overwrite<{ a: string; b: number }, { b?: boolean }> // $ExpectType Compact & { b?: boolean | undefined; }> 46 | 47 | // 48 | // Diff 49 | // 50 | 51 | type Diff1 = Diff<{ a: string; b: number }, 'b'> // $ExpectType Compact<{ a: string; } & { b?: number | undefined; }> 52 | 53 | // 54 | // RowLacks 55 | // 56 | 57 | declare function rowlacks1(x: RowLacks<{ a: string; b: number }, 'a'>): void 58 | // $ExpectError 59 | rowlacks1({ a: 'foo', b: 1 }) 60 | declare function rowlacks2(x: RowLacks<{ a: string; b: number }, 'c'>): void 61 | rowlacks2({ a: 'foo', b: 1 }) 62 | 63 | // 64 | // Exact 65 | // 66 | 67 | declare function exactf1>(a: T): void 68 | declare const exact1: { a: string } 69 | declare const exact2: { a: string; b: number } 70 | declare const exact3: { a: string; b: any } 71 | exactf1(exact1) 72 | // $ExpectError 73 | exactf1(exact2) 74 | // $ExpectError 75 | exactf1(exact3) 76 | 77 | // 78 | // KeysOfType 79 | // 80 | type KeysOfType1 = KeysOfType<{ a: string; b: never }, never> // $ExpectType "b" 81 | type KeysOfType2 = KeysOfType<{ a: string; b: string }, string> // $ExpectType "a" | "b" 82 | type KeysOfType3 = KeysOfType<{ a: string; b: string | boolean }, string> // $ExpectType "a" 83 | type KeysOfType4 = KeysOfType<{ a: string; b?: string }, string> // $ExpectType "a" 84 | 85 | // 86 | // AnyTuple 87 | // 88 | 89 | declare function anytuplef1(x: T): T 90 | declare const anytuple1: [number] 91 | declare const anytuple2: [number, string] 92 | declare const anytuple3: [number, string, boolean] 93 | declare const anytuple4: Array 94 | anytuplef1(anytuple1) 95 | anytuplef1(anytuple2) 96 | anytuplef1(anytuple3) 97 | // $ExpectError 98 | anytuplef1(anytuple4) 99 | 100 | // 101 | // DeepReadonly 102 | // 103 | 104 | interface Foo { 105 | bar: { 106 | baz: string 107 | quux: Array<{ barbaz: number }> 108 | } 109 | } 110 | 111 | type ReadonlyFoo = DeepReadonly 112 | type DeepReadonly1 = ReadonlyFoo['bar'] // $ExpectType DeepReadonlyObject<{ baz: string; quux: { barbaz: number; }[]; }> 113 | type DeepReadonly2 = ReadonlyFoo['bar']['quux'] // $ExpectType DeepReadonlyArray<{ barbaz: number; }> 114 | type DeepReadonly3 = ReadonlyFoo['bar']['quux'][number] // $ExpectType DeepReadonlyObject<{ barbaz: number; }> 115 | declare const readonly1: ReadonlyFoo 116 | // $ExpectError 117 | readonly1.bar.quux[1].barbaz = 1 118 | 119 | // 120 | // TaggedUnionMember 121 | // 122 | 123 | type TaggedUnionMemberA = { tag: 'A'; a: string } 124 | type TaggedUnionMemberB = { tag: 'B'; b: number } 125 | type TaggedUnionMemberC = TaggedUnionMemberA | TaggedUnionMemberB 126 | type TaggedUnionMember1 = TaggedUnionMember // $ExpectType TaggedUnionMemberA 127 | 128 | // 129 | // RequiredKeys 130 | // 131 | 132 | type BarForRequired = { 133 | a: number 134 | b: Date 135 | x?: string 136 | y?: Date 137 | } 138 | 139 | type BarRequiredKeys = RequiredKeys // $ExpectType "a" | "b" 140 | // $ExpectType "a" | "b" 141 | type RequiredKeysIndexSignature = RequiredKeys<{ 142 | [x: string]: any 143 | a: number 144 | b: Date 145 | x?: string 146 | y?: Date 147 | }> 148 | type RequiredKeysEmpty = RequiredKeys<{}> // $ExpectType never 149 | 150 | // 151 | // OptionalKeys 152 | // 153 | 154 | type BarForOptional = { 155 | a: number 156 | b: Date 157 | x?: string 158 | y?: Date 159 | } 160 | 161 | type BarOptionalKeys = OptionalKeys // $ExpectType "x" | "y" 162 | // $ExpectType "x" | "y" 163 | type OptionalKeysIndexSignature = OptionalKeys<{ 164 | [x: string]: any 165 | a: number 166 | b: Date 167 | x?: string 168 | y?: Date 169 | }> 170 | type OptionalKeysEmpty = OptionalKeys<{}> // $ExpectType never 171 | -------------------------------------------------------------------------------- /docs/modules/index.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: index.ts 3 | nav_order: 1 4 | parent: Modules 5 | --- 6 | 7 | # index overview 8 | 9 | Added in v0.3.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [DeepReadonlyArray (interface)](#deepreadonlyarray-interface) 16 | - [AnyTuple (type alias)](#anytuple-type-alias) 17 | - [Compact (type alias)](#compact-type-alias) 18 | - [DeepReadonly (type alias)](#deepreadonly-type-alias) 19 | - [Diff (type alias)](#diff-type-alias) 20 | - [Equals (type alias)](#equals-type-alias) 21 | - [Exact (type alias)](#exact-type-alias) 22 | - [KeysOfType (type alias)](#keysoftype-type-alias) 23 | - [OptionalKeys (type alias)](#optionalkeys-type-alias) 24 | - [Overwrite (type alias)](#overwrite-type-alias) 25 | - [RequiredKeys (type alias)](#requiredkeys-type-alias) 26 | - [RowLacks (type alias)](#rowlacks-type-alias) 27 | - [TaggedUnionMember (type alias)](#taggedunionmember-type-alias) 28 | 29 | --- 30 | 31 | # DeepReadonlyArray (interface) 32 | 33 | **Signature** 34 | 35 | ```ts 36 | export interface DeepReadonlyArray extends ReadonlyArray> {} 37 | ``` 38 | 39 | Added in v0.3.0 40 | 41 | # AnyTuple (type alias) 42 | 43 | **Signature** 44 | 45 | ```ts 46 | export type AnyTuple = Array & { '0': any } 47 | ``` 48 | 49 | **Example** 50 | 51 | ```ts 52 | import { AnyTuple } from 'typelevel-ts' 53 | 54 | function f(x: T): T { 55 | return x 56 | } 57 | const x: [number] = [1] 58 | const y: [number, string] = [1, 'a'] 59 | const z: [number, string, boolean] = [1, 'a', true] 60 | f(x) 61 | f(y) 62 | f(z) 63 | // $ExpectError 64 | // f([1, 2, 3]) 65 | ``` 66 | 67 | Added in v0.3.0 68 | 69 | # Compact (type alias) 70 | 71 | **Signature** 72 | 73 | ```ts 74 | export type Compact = { [K in keyof A]: A[K] } 75 | ``` 76 | 77 | Added in v0.3.0 78 | 79 | # DeepReadonly (type alias) 80 | 81 | **Signature** 82 | 83 | ```ts 84 | export type DeepReadonly = A extends Array ? DeepReadonlyArray : DeepReadonlyObject 85 | ``` 86 | 87 | **Example** 88 | 89 | ```ts 90 | import { DeepReadonly } from 'typelevel-ts' 91 | 92 | interface Foo { 93 | bar: { 94 | baz: string 95 | quux: Array<{ barbaz: number }> 96 | } 97 | } 98 | 99 | type ReadonlyFoo = DeepReadonly 100 | export declare const x: ReadonlyFoo 101 | // $ExpectError 102 | // x.bar.quux[1].barbaz = 1 103 | ``` 104 | 105 | Added in v0.3.0 106 | 107 | # Diff (type alias) 108 | 109 | **Signature** 110 | 111 | ```ts 112 | export type Diff = Compact< 113 | { [K in Exclude]: A[K] } & { [K in OK]?: A[K] } 114 | > 115 | ``` 116 | 117 | **Example** 118 | 119 | ```ts 120 | import { Diff } from 'typelevel-ts' 121 | 122 | export type Result = Diff<{ a: string; b: number }, 'b'> // { a: string; b?: number } 123 | ``` 124 | 125 | Added in v0.3.0 126 | 127 | # Equals (type alias) 128 | 129 | Returns the string literal 'T' if `A` and `B` are equal types, 'F' otherwise 130 | 131 | **Signature** 132 | 133 | ```ts 134 | export type Equals = (() => C extends Compact ? 'T' : 'F') extends () => C extends Compact ? 'T' : 'F' 135 | ? 'T' 136 | : 'F' 137 | ``` 138 | 139 | **Example** 140 | 141 | ```ts 142 | import { Equals } from 'typelevel-ts' 143 | 144 | export type Result1 = Equals // "T" 145 | export type Result2 = Equals // "F" 146 | ``` 147 | 148 | Added in v0.3.0 149 | 150 | # Exact (type alias) 151 | 152 | **Signature** 153 | 154 | ```ts 155 | export type Exact = A & Record, never> 156 | ``` 157 | 158 | **Example** 159 | 160 | ```ts 161 | import { Exact } from 'typelevel-ts' 162 | 163 | function f>(a: T): void {} 164 | f({ a: 'a' }) 165 | // $ExpectError 166 | // f({ a: 'a', b: 1 }) 167 | ``` 168 | 169 | Added in v0.3.0 170 | 171 | # KeysOfType (type alias) 172 | 173 | Picks only the keys of a certain type 174 | 175 | **Signature** 176 | 177 | ```ts 178 | export type KeysOfType = { [K in keyof A]-?: A[K] extends B ? K : never }[keyof A] 179 | ``` 180 | 181 | **Example** 182 | 183 | ```ts 184 | import { KeysOfType } from 'typelevel-ts' 185 | 186 | export type Result = KeysOfType<{ a: string; b: string | boolean; c: boolean; d: string }, string> // "a" | "d" 187 | ``` 188 | 189 | Added in v0.3.0 190 | 191 | # OptionalKeys (type alias) 192 | 193 | Extracts optional keys as a literal type union 194 | 195 | **Signature** 196 | 197 | ```ts 198 | export type OptionalKeys = { [K in keyof T]: T extends Record ? never : K } extends { 199 | [_ in keyof T]: infer U 200 | } 201 | ? {} extends U 202 | ? never 203 | : U 204 | : never 205 | ``` 206 | 207 | **Example** 208 | 209 | ```ts 210 | import { OptionalKeys } from 'typelevel-ts' 211 | 212 | type A = { a: string; b: number; x?: string; y?: number } 213 | export type Result = OptionalKeys // "x" | "y" 214 | ``` 215 | 216 | Added in v0.3.0 217 | 218 | # Overwrite (type alias) 219 | 220 | **Signature** 221 | 222 | ```ts 223 | export type Overwrite = Compact & B> 224 | ``` 225 | 226 | **Example** 227 | 228 | ```ts 229 | import { Overwrite } from 'typelevel-ts' 230 | 231 | export type Result = Overwrite<{ a: string; b: number }, { b: boolean }> // { a: string; b: boolean } 232 | ``` 233 | 234 | Added in v0.3.0 235 | 236 | # RequiredKeys (type alias) 237 | 238 | Extracts required keys as a literal type union 239 | 240 | **Signature** 241 | 242 | ```ts 243 | export type RequiredKeys = { [K in keyof T]: {} extends Pick ? never : K } extends { [_ in keyof T]: infer U } 244 | ? {} extends U 245 | ? never 246 | : U 247 | : never 248 | ``` 249 | 250 | **Example** 251 | 252 | ```ts 253 | import { RequiredKeys } from 'typelevel-ts' 254 | 255 | type A = { a: string; b: number; x?: string; y?: number } 256 | export type Result = RequiredKeys // "a" | "b" 257 | ``` 258 | 259 | Added in v0.3.0 260 | 261 | # RowLacks (type alias) 262 | 263 | Encodes the constraint that a given object `A` does not contain specific keys `K` 264 | 265 | **Signature** 266 | 267 | ```ts 268 | export type RowLacks = A & Record, never> 269 | ``` 270 | 271 | **Example** 272 | 273 | ```ts 274 | import { RowLacks } from 'typelevel-ts' 275 | 276 | // function f(x: RowLacks<{ a: string; b: number }, 'a' | 'b'>): void {} 277 | // $ExpectError 278 | // f({ a: 'a', b: 1 }) 279 | function g(x: RowLacks<{ a: string; b: number }, 'c'>): void {} 280 | g({ a: 'a', b: 1 }) // ok 281 | ``` 282 | 283 | Added in v0.3.0 284 | 285 | # TaggedUnionMember (type alias) 286 | 287 | Extracts the type of a member of a tagged union 288 | 289 | **Signature** 290 | 291 | ```ts 292 | export type TaggedUnionMember = Extract< 293 | A, 294 | Record 295 | > 296 | ``` 297 | 298 | **Example** 299 | 300 | ```ts 301 | import { TaggedUnionMember } from 'typelevel-ts' 302 | 303 | type A = { tag: 'A'; a: string } 304 | type B = { tag: 'B'; b: number } 305 | type C = A | B 306 | export type Result = TaggedUnionMember // A 307 | ``` 308 | 309 | Added in v0.3.0 310 | --------------------------------------------------------------------------------