Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/gregros/declare-it
https://github.com/gregros/declare-it
Last synced: 9 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/gregros/declare-it
- Owner: GregRos
- License: mit
- Created: 2024-04-01T16:31:34.000Z (9 months ago)
- Default Branch: master
- Last Pushed: 2024-04-01T16:36:08.000Z (9 months ago)
- Last Synced: 2024-04-14T07:42:53.003Z (9 months ago)
- Language: TypeScript
- Size: 649 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# declare-it
[![Node.js CI](https://github.com/GregRos/declare-it/actions/workflows/push.yaml/badge.svg)](https://github.com/GregRos/declare-it/actions/workflows/push.yaml)
[![npm](https://img.shields.io/npm/v/declare-it)](https://www.npmjs.com/package/declare-it)`declare-it` is a TypeScript library for writing compile-time tests for your type declarations. It helps you by registering your compile-time tests with your test framework so they appear alongside other tests.
```bash
yarn add -D declare-it
````declare-it` only supports simple, direct assertions on specific types together with their negations:
- A ≡ B — `to_equal` — Type **A** is equal to type **B**.
- A ⊆ B — `to_subtype` — Type **A** is a subtype of **B**.
- A ⊇ B — `to_supertype` — Type **A** is a supertype of **B**.
- A ⊂ B — `to_strictly_subtype` — Type **A** is a subtype of **B**, but not equal to it.
- A ⊃ B — `to_strictly_supertype` — Type **A** is a supertype of **B**, but not equal to it.
Here is how using it looks like:
```ts
import { declare, type } from "declare-it"
declare.it("number is number", expect => {
expect(type).to_equal(type)
expect(type).not.to_equal(type)
})
```You declare test cases using `declare.it` or `declare.test`, just like you would with normal tests. Your code will compile only if your tests pass. You can also place your tests inside the `describe` blocks defined by other frameworks, though there is no `declare.describe` function.
Each test case receives an `expect` function as an argument. This is what you use to make assertions. The inputs to this function are created using either `type` or `type_of`. You use `type` when you want to specify a specific type explicitly, using the following DSL-like syntax:
```ts
expect(type<5>).to_subtype(type)
```Note that you don’t actually call the `type` function, you just specify its type parameter. It’s a bit weird, but it works quite well.
You use `type_of` when you want to make an assertion about the type of an expression. It’s best to provide it expressions that have a predetermined type, rather than ones where the type can be inferred, such as the return types of methods.
You will usually use it as an input to `expect` and compare it to an explicitly specified type:
```ts
expect(type_of(thing.method())).to_equal(type)
```If an assertion fails, the message will include the name of the test and what was the cause for the failure. It doesn’t go into too much detail, but it’s a much finer and more specific test than using `ts-expect-error` comments.
The error messages are a bit weird, but they’re also distinctive and concise. They’re all assignability errors, with the actual reason for the failure – as well as the name of the test – being encoded into one of the types.
Here is an example, though the specific message can change and shouldn’t be considered part of the library’s API.
```
Argument of type '() => [2, 1]' is not assignable to parameter of type '["❌ 𝘁𝗵𝗲 𝘁𝘆𝗽𝗲 ❮", [1, 2], "❯ 𝗱𝗼𝗲𝘀 𝗻𝗼𝘁 𝘀𝘂𝗯𝘁𝘆𝗽𝗲 ❮", [2, 1], "❯ 𝗔𝗧 𝗧𝗘𝗦𝗧 ⸨ [1, 2] ⊈ [2, 1] ⸩"]'.
```# Test registration
`declare-it` registers its tests with whatever unit testing framework it detects. Here is how that looks like, using `jest`:
```
PASS src/test/core/tuples.spec.ts
√ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: [1] ⊆ [1] (7 ms)
√ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: [1, 2] ⊈ [2, 1]
√ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: 1[] ⊂ readonly 1[]
√ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: readonly 1[] ≡ Readonly<1[]>
√ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: 1[] ≡ Array<1>
√ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: [1] ⊂ [1?]
```**Note that this is a convenience feature** designed to help you keep track of tests. No testing actually takes place during runtime. Your real test runner is the TypeScript compiler and its test process is just **compiling your code.**
In fact, you don’t even need to run any code for testing to take place, and doing so is purely optional.
# Skipping tests
You can mark tests as skipped. This is currently only possible by modifying the code – you can’t filter out specific tests dynamically.
To do this, you need to replace `declare.it` calls with `declare.it.skip`. All assertions involving `declare-it`’s `expect` will automatically pass and the test will be registered as skipped with your unit testing framework.
```ts
declare.it.skip("this is not ready yet", expect => {
expect(type_of(obj.method())).to_equal(type)
}
```Note that this doesn’t affect any other code inside the test case, so even if you do this, code might fail to compile due to other reasons.