{"id":18472802,"url":"https://github.com/gregros/declare-it","last_synced_at":"2026-02-16T23:35:26.568Z","repository":{"id":231206782,"uuid":"780512824","full_name":"GregRos/declare-it","owner":"GregRos","description":"Accurately test type declarations.","archived":false,"fork":false,"pushed_at":"2025-04-01T15:16:45.000Z","size":12127,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-20T07:14:53.705Z","etag":null,"topics":["library","package","testing","type-declarations","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GregRos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-04-01T16:31:34.000Z","updated_at":"2025-05-04T21:15:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"4f197af4-7e70-4e08-b0c7-64b22b984ef2","html_url":"https://github.com/GregRos/declare-it","commit_stats":null,"previous_names":["gregros/declare-it"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/GregRos/declare-it","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregRos%2Fdeclare-it","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregRos%2Fdeclare-it/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregRos%2Fdeclare-it/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregRos%2Fdeclare-it/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GregRos","download_url":"https://codeload.github.com/GregRos/declare-it/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GregRos%2Fdeclare-it/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29524333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T21:45:09.491Z","status":"ssl_error","status_checked_at":"2026-02-16T21:44:58.452Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["library","package","testing","type-declarations","typescript"],"created_at":"2024-11-06T10:22:27.340Z","updated_at":"2026-02-16T23:35:26.552Z","avatar_url":"https://github.com/GregRos.png","language":"TypeScript","readme":"# declare-it\n[![npm version](https://img.shields.io/npm/v/declare-it.svg)](https://www.npmjs.com/package/declare-it)\n[![npm downloads](https://img.shields.io/npm/dm/declare-it.svg)](https://www.npmjs.com/package/declare-it)\n[![GitHub Workflow Status](https://github.com/gregros/declare-it/actions/workflows/push.yaml/badge.svg)](https://github.com/gregros/declare-it/actions/workflows/push.yaml)\n\nTest your TypeScript type declarations with style! \n\nPlugs into your favorite runtime test framework.\n\n- 👷‍♂️ Write actual test cases, with titles and everything!\n\n- 📐 **Simple** but **incredibly accurate** type assertions\n\n- 🧼 A clean and legible API, with a dash of DevEx magic.\n\n- 📜 Human-readable compile-time errors!\n\n- 🪄 Keeps track of tests by registering them with your test framework!\n\n- 💁‍♀️ No plugins or configuration required!\n\nHere’s what it looks like:\n\n```ts\nimport {declare, type, type_of} from \"declare-it\"\n\ndeclare.it(\"tests basic math\", expect =\u003e {\n    expect( type\u003c1\u003e ).to_subtype( type\u003cnumber\u003e )\n\n    expect(\n//  ↓ type being compared:\n        type\u003c1\u003e \n//  ↓ type assertion:\n    ).to_subtype( \n//  ↓ comparing against:\n        type\u003cnumber\u003e \n//  ↓ chain another assertion:\n    ).and.to_subtype(\n//  ↓ infer the type of a value:\n        type_of(val)\n    )\n})\n```\n\nGet it now!\n\n```bash\nyarn add -D declare-it\n```\n\n```bash\nnpm install --save-dev declare-it\n```\n# Declaring test cases\nYou declare test cases using the `declare.it` function, which takes a callback that has one parameter.\n\nThis is your `expect` function. It’s what you use to make assertions about types. Every `expect` function belongs to a test case and knows its title.\n\n```ts\ndeclare.it(\"your test title\", expect =\u003e {\n    expect(...).to_equal(...)\n})\n```\n\n**These test cases don’t actually execute at runtime.** Your test runner is the compiler, and it “runs” your tests by compiling your code.\n\nThat also means these test cases can contain any code you want. They can be async too. It doesn’t matter; it just has to compile.\n\n```ts\ndeclare.it(\"side-effects?\", async expect =\u003e {\n    let x = await callSomeFunction()\n    \n    expect(type_of(x)).to_equal(type\u003c1\u003e)\n})\n```\n# Referencing types\nWhen using **declare-it**, to make assertions about types you need to reference them in a special way. \n\nThere are two options:\n\n- Using the explicit `type\u003cYourType\u003e`\n- Using inferred `type_of(yourValue)`\n\nSo either specify the type explicitly:\n\n```ts\ntype\u003cnumber\u003e\ntype\u003c1\u003e\ntype\u003cstring\u003e\n```\n\nOr infer it from a variable:\n\n```ts\ntype_of(variable)\n```\n\nJust don’t use it with literals:\n\n```ts\ntype_of(\"hello world\")\n```\n\nLiterals don’t have declared types, so the type you get might not be what you expect. \n# Being assertive\n**declare-it**’s type assertions all work and look the same. They’re methods on the `expect` object you get by calling:\n\n```ts\nexpect( \n    type\u003cSomeType\u003e \n)\n```\n\nThey all start with `to_`, such as:\n```ts\n// Inside a declare.it clause:\nexpect( \n    type\u003c1\u003e \n).to_subtype( \n    type\u003cnumber\u003e \n)\n```\n\nThey can all be inverted by using `.not`, like this:\n\n```ts\n// Inside a declare.it clause:\nexpect( \n    type\u003c1\u003e \n).not.to_subtype( \n    type\u003cstring\u003e \n)\n```\n\nAnd you can also chain them by tacking `.and` like this:\n\n```ts\n// Inside a declare.it clause:\nexpect( \n    type\u003c1\u003e \n).to_subtype( \n    type\u003cnumber\u003e \n).and.to_subtype( \n    type\u003cunknown\u003e \n)\n```\n\nYou can do both, but you’ll need to prefix every inverted assertion with `not.` for the sake of readability:\n\n```ts\n// Inside a declare.it clause:\nexpect( \n    type\u003c1\u003e \n).not.to_subtype(\n    type\u003c2\u003e \n).and.not.to_subtype( \n    type\u003c3\u003e \n)\n```\n\nLet’s take a look at the assertions you can make.\n# to_equal [ L ≡ R ]\nThis the strictest assertion **declare-it** has in its arsenal. It checks if two types are **interchangeable**. \n\nIt will only pass if you can replace one type with another *in all contexts*. Any code that compiles using one of them has to also compile with the other. \n\nThat means identical modifiers on properties:\n```ts\nexpect(\n    type\u003c{a: 1}\u003e\n).not.to_equal(\n    type\u003c{readonly a: 1}\u003e\n).and.not.to_equal(\n    type\u003c{a: 1}\u003e\n)\n```\n\nIdentical key declarations:\n```ts\nexpect(\n    type\u003c{1: 1}\u003e\n).not.to_equal(\n    type\u003c{\"1\": 1}\u003e\n)\n```\n\nIdentical call signatures:\n```ts\nexpect(\n    type\u003c() =\u003e 1\u003e\n).not.to_equal(\n    type\u003c \u003cT\u003e() =\u003e 1 \u003e\n)\n```\n\nAnd everything else!\n# to_subtype [ L ⊆ R ]\nThis assertion checks if one type `L` is a **subtype of** another type `R`. This means:\n\n- `L` has all of the *structure* of `R`, like members, call signatures, and so on. \n- A value of type `L` can be assigned to a variable of type `R`.\n- And finally, you can use `L` instead of `R` in generic type constraints.\n\nThat means this code has to compile:\n\n```ts\nconst right: R = null! as L\n```\n\nBut this code has to compile too:\n```ts\ntype Subtype_Of\u003cL extends R, R\u003e = null\ntype L_Subtypes_R = Subtype_Of\u003cL, R\u003e\n```\n\nThis is an extremely useful assertion. By constructing the right type to compare against, you can make all kinds of complex statements about the type being tested.\n\nFor example, you can check your type has a specific property using:\n\n```ts\nexpect(\n    type\u003cTestedType\u003e\n).to_subtype(\n    type\u003c {yourKey: YourValue } \u003e\n)\n```\n## Negation [ L ⊈ R ]\nThe negation is also quite useful, as it lets you make sure a type *doesn’t* have some structure you don’t want, like an indexer:\n\n```ts\nexpect(...).not.to_subtype(\n    type\u003c{\n        [x: string]: unknown\n    }\u003e\n)\n```\n\nYou can also use it to make sure one of your methods *isn’t* callable with a set of types:\n\n```ts\nexpect(\n    type\u003cTestedType\u003e\n).not.to_subtype(\n    type\u003c{\n        method(x: number): unknown\n    }\u003e\n)\n```\n# to_supertype [ L ⊇ R ]\nThis assertion checks the opposite — that `L` is a supertype of `R`. This means:\n\n- `R` has all of the structure of `L`\n- A value of type `R` is assignable to a variable of type `L`\n- You can use `R` instead of `L` to satisfy type constraints.\n\nIt’s basically the same check as `to_subtype`, but with the operands inverted. \n# to_resemble [ L ≈ R ]\nThis combines the two previous assertions. It can also be written as:\n\nOr as:\n\n```ts\nexpect(\n    type\u003cYourType\u003e\n).to_subtype(\n    type\u003cOtherType\u003e\n).and.to_supertype(\n    type\u003cOtherType\u003e\n)\n```\n\nIn other words, it lets you check whether two types **are mutual subtypes of each other**, having the same structure.\n\nIn particular, the following code has to compile:\n\n```ts\nconst right: R = null! as L\nconst left: L = null! as R\n```\n\nAs well as the following code:\n\n```ts\ntype L_Subtypes_R = Subtype_Of\u003cL, R\u003e\ntype R_Subtypes_L = Subtype_Of\u003cR, L\u003e\n```\n\nWhich tells you that the right-hand type is assignable to the left-hand one. However, it’s not as strict or accurate as `to_equal`. \n## Negation [ L ≉ R ]\nThe negation — `not.to_resemble` — means two types aren’t the same. One way to use it is to check that a type isn’t `any`:\n\n```ts\nexpect(\n    type\u003cX\u003e\n).not.to_resemble(\n    type\u003cany\u003e\n)\n```\n# Dealing with failure\nHere’s what TypeScript says when an assertion fails:\n\n```\nsrc/test/core/primitives.spec.ts:14:33 - error TS2345: \nArgument of type \n'{ (): (_: never) =\u003e number; (_: never): number; }' \nis not assignable to parameter of type \n'[\"                                              \", \n\"❌ 𝗔𝗧 𝗧𝗘𝗦𝗧 “1 ⊂ number” ❱➤ \n𝗧𝗛𝗘 𝗧𝗬𝗣𝗘 (\", 1, \") 𝗗𝗢𝗘𝗦 𝗡𝗢𝗧 𝗦𝗨𝗣𝗘𝗥-𝗧𝗬𝗣𝗘 (\", number, \")                                                    \"]'.\n```\n\nIt’s a failure message with some garbage at the start! Let’s take a closer look, without the unnecessary characters:\n\n```\n❌ 𝗔𝗧 𝗧𝗘𝗦𝗧 “1 ⊂ number” ❱➤ \n𝗧𝗛𝗘 𝗧𝗬𝗣𝗘 (\", 1, \") 𝗗𝗢𝗘𝗦 𝗡𝗢𝗧 𝗦𝗨𝗣𝗘𝗥-𝗧𝗬𝗣𝗘 (\", number, \")\n```\n\nHere we can see:\n\n1. A big red ❌, always reassuring.\n2. Bold text 😮\n3. The name of the test where the failure happened.\n4. Badass Unicode arrow thingy.\n5. The `L` type — the one that went into the `expect` function.\n6. The `R` type — the one that went into the assertion function.\n7. A description of the problem.\n\nAnd of course, you also have the trace pointing to the line where the failure occurred.\n\nUse this information wisely! \n# Automagic registration\n**declare-it** comes with a bonus feature. It will actually talk to your test framework — provided you have one — and tell it about the tests you’re making.\n\nThe tests still run as part of compilation, but you’ll have a pretty list so you can feel proud of yourself for writing them. Here’s how it looks like in Jest:\n\n```\n PASS  src/test/core/any.spec.ts\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: any is only equal to any (1 ms)\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: {a: any} ≡ {a: any}\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: {a: any} ⊈ {a: 1}\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: {a: any, b: any} ⊂ {a: any}\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: 3 level nested\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: 5 level nested\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: two identical disj types\n  √ 💭 𝗧𝗬𝗣𝗘-𝗢𝗡𝗟𝗬 𝗧𝗘𝗦𝗧: two differnt disj types\n```\n\nAutomagic registration will examine your environment, try to import various packages, and generally look around. If it doesn’t find anything, it will print the same messages to the console.\n\nAutomagic registration uses the [what-the-test](https://github.com/gregros/what-the-test) package, which currently supports:\n\n- Jasmine\n- Mocha\n- Jest\n- Ava\n## Manual configuration\nIf the automagic stuff doesn’t work out, you can always configure `declare-it` manually using the `declare.setup` function:\n\n```ts\nimport {declare} from \"declare-it\"\n\n// Emit to the console:\ndeclare.setup(\"console\")\n\n// Don't emit at all:\ndeclare.setup(false)\n\n// Use ava:\ndeclare.setup(\"ava\")\n\n// Use jest:\ndeclare.setup(\"jest\")\n```\n# Skipping tests\nYou can skip compile-time tests in a similar way to how you might skip runtime test. \n\nJust prefix the test case declaration with `.skip`:\n\n```ts\ndeclare.it.skip(\n    \"this is a skipped test, so no error\", expect =\u003e {\n    expect(type\u003cnumber\u003e).to_equal(type\u003cstring\u003e)\n})\n```\n\nIt will make your assertions always pass! It will also register the test as skipped with your test framework.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgregros%2Fdeclare-it","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgregros%2Fdeclare-it","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgregros%2Fdeclare-it/lists"}