Comparing version 1.2.0 to 1.3.0
{ | ||
"name": "ts-xor", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "Compose custom types containing mutually exclusive keys, using this generic Typescript helper type.", | ||
@@ -21,2 +21,14 @@ "main": "./dist/index.js", | ||
"sideEffects": false, | ||
"scripts": { | ||
"codegen": "node ./src/xorFactory.js > ./src/types/xor.ts", | ||
"prebuild": "npm run codegen", | ||
"build": "tsup src/index.ts --format esm,cjs --dts --sourcemap --clean", | ||
"pretest": "npm run codegen", | ||
"test": "npm run test:smoke && npm run test:unit && npm run test:package", | ||
"test:smoke": "tsc -p . --noEmit", | ||
"test:unit": "sh scripts/run-tests.sh", | ||
"test:package": "publint", | ||
"preversion": "npm run build && npm test", | ||
"postpublish": "git push --tags" | ||
}, | ||
"repository": { | ||
@@ -43,11 +55,3 @@ "type": "git", | ||
"typescript": "^5.2.2" | ||
}, | ||
"scripts": { | ||
"build": "tsup src/index.ts --format esm,cjs --dts --sourcemap --clean", | ||
"test": "npm run test:smoke && npm run test:unit && npm run test:package", | ||
"test:smoke": "tsc -p . --noEmit", | ||
"test:unit": "sh scripts/run-tests.sh", | ||
"test:package": "publint", | ||
"preversion": "npm run build && npm test" | ||
} | ||
} | ||
} |
@@ -14,3 +14,3 @@ [![npm version](https://badgen.net/npm/v/ts-xor?color=green)](https://www.npmjs.com/package/ts-xor) | ||
The npm package `ts-xor` introduces the new mapped type `XOR` that helps you compose your own custom TypeScript types containing mutually exclusive keys. | ||
The tiny npm package `ts-xor` introduces the new mapped type `XOR` that helps you compose your own custom TypeScript types containing mutually exclusive keys for zero runtime overhead. | ||
@@ -64,6 +64,8 @@ ## Description | ||
Notice in the example above, that when using XOR each "variant" of the resulting type contains all keys of one source type plus all keys of the other. At the same time those keys of the second type are defined as _optional_ while additionally they are also typed as _undefined_. | ||
Notice in the example above, that when using `XOR`, each union branch of the resulting type contains all keys of one source type plus all keys of the other. At the same time, in each variant, those keys of the other type are defined as _optional_ while additionally they are also typed as _undefined_. | ||
This trick will not only forbid defining keys of both source types at the same time (since the type of each key is explicitly `undefined`), but also _allow_ us to not need to define all keys all of the time since each set of keys is optional on each variant. | ||
This trick will not only forbid having keys of both source types defined at the same time (since the type of each key is explicitly `undefined`), but also _allow_ us to not need to define all keys all of the time since each set of keys is optional on each variant. | ||
>_Fun fact: The actual TypeScript code for `XOR` [is generated programmatically](https://github.com/maninak/ts-xor/pull/27) using the TypeScript Compiler API._ 🦾 | ||
## Installation | ||
@@ -79,4 +81,2 @@ | ||
### A simple scenario | ||
```typescript | ||
@@ -96,4 +96,29 @@ import type { XOR } from 'ts-xor' | ||
### A realistic scenario | ||
### XORing more than two types | ||
If you want to create a type as the product of the logical XOR operation between multiple types (more than two and even up to 200), then just pass them as additional comma-separated generic params. | ||
```typescript | ||
let test: XOR<A, B, C, D, E, F> | ||
``` | ||
`ts-xor` can easily handle up to 200 generic params. 💯 | ||
### Pattern 1: Typing a fetcher returning data XOR error | ||
Using `XOR` we can type a function that returns either the data requested from an API or a response object like so: | ||
```ts | ||
type FetchResult<P extends object> = XOR< | ||
{ data: P }, | ||
{ error: FetchError<P> }, | ||
> | ||
``` | ||
Now TypeScript has all the necessary information to infer if the `FetchResult` contains a `data` or `error` key _at compile time_ which results in very clean, yet strictly typed, handling code. | ||
![data or error intellisense demo](./assets/dataOrError-intellisense.gif) | ||
### Pattern 2: Typing an API's response shape | ||
Let's assume that we have the following spec for a weather forecast API's response: | ||
@@ -107,4 +132,2 @@ | ||
```typescript | ||
import type { XOR } from 'ts-xor' | ||
type ForecastAccuracy = XOR<{ '1h': number }, { '3h': number }> | ||
@@ -142,22 +165,2 @@ | ||
### XORing more than two types | ||
If you want to create a type as the product of the logical XOR operation between multiple types (more than two), then nest the generic params. | ||
```typescript | ||
import type { XOR } from 'ts-xor' | ||
interface A { a: string } | ||
interface B { b: string } | ||
interface C { c: string } | ||
let test: XOR<A, XOR<B, C>> | ||
test = { a: '' } // OK | ||
test = { b: '' } // OK | ||
test = { c: '' } // OK | ||
test = { a: '', c: '' } // error | ||
test = {} // error | ||
``` | ||
## Tests and coverage | ||
@@ -164,0 +167,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
820051
12
537
187
1