tsd

repository·main·Indexed 25 days ago

https://github.com/tsdjs/tsd

A tool for testing TypeScript type definitions (.d.ts files) using static analysis and specialized assertion constructs in .test-d.ts files. It provides a CLI and a programmatic API to verify type identity, assignability, deprecation status, and documentation comments through assertions such as expectType, expectAssignable, and expectError.

Tokens
4.5K
Snippets
8
Records
28
Agent score
32%

What's inside tsd

  1. Understand the tsd Order of Operations

    main

    When running tsd, the tool follows these steps to find and execute tests:

    1. Locate package.json: Must be in the current or specified directory.
    2. Find .d.ts file: Checks the types field in package.json, or manually specified path. If neither is found, it looks for a file named after the main field in package.json or index.d.ts.
    3. Find .test-d.ts files: Searches the project root, a specific folder (default: test-d), or files specified via CLI/programmatically.
    4. Compile and Analyze: Runs files through the TypeScript compiler and performs static analysis.
    5. Verify Assertions: Checks errors against your expect... assertions and reports mismatches.
  2. How tsd works

    main

    tsd allows you to write tests for your TypeScript type definitions (.d.ts files) by creating files with the .test-d.ts extension.

    Unlike standard TypeScript files, these .test-d.ts files are not executed or compiled in the traditional sense. Instead, tsd parses them for special assertion constructs and statically analyzes them against your type definitions.

    To run tests, use the CLI to test an entire project:

    [npx] tsd [path]

    By default, tsd searches for the main .d.ts file in the current or specified directory and looks for tests in the same directory or a test-d sub-directory.

  3. Strict vs Loose type assertions

    main

    tsd distinguishes between strict identity and assignability:

    • Strict Assertions: expectType<T>(expression) fails if the type is not identical to T. For example, if the expression returns string and you expect string | number, the test will fail.
    • Loose Assertions: expectAssignable<T>(expression) passes if the type of the expression is assignable to T. Use this when you want to allow broader types (e.g., expecting string | number when the actual type is string).
    import {expectType, expectAssignable} from 'tsd';
    import concat from '.';
    
    expectType<string>(concat('foo', 'bar'));
    expectAssignable<string | number>(concat('foo', 'bar'));
  4. Use top-level await in tests

    main

    If your type definitions involve Promise returns, you can use top-level await directly within your .test-d.ts files to resolve values for assertion.

    import {expectType, expectError} from 'tsd';
    import concat from '.';
    
    expectType<Promise<string>>(concat('foo', 'bar'));
    
    expectType<string>(await concat('foo', 'bar'));
    
    expectError(await concat(true, false));
  5. Configure tsd via package.json

    main

    You can configure tsd settings directly in your package.json under a tsd key.

    Custom Test Directory By default, tsd looks in test-d. To use a different directory:

    {
    	"tsd": {
    		"directory": "my-test-dir"
    	}
    }

    Custom TypeScript Compiler Options You can override default compilerOptions (like strict, jsx, target, etc.) using the compilerOptions key. Note that moduleResolution and skipLibCheck cannot be overridden via this method.

    {
    	"name": "my-module",
    	"tsd": {
    		"compilerOptions": {
    			"strict": false
    		}
    	}
    }
  6. Use tsd assertions in .test-d.ts files

    main

    To test a type definition, create a .test-d.ts file that imports the types and uses tsd assertion functions.

    Example: Testing a concat module

    index.d.ts

    declare const concat: {
    	(value1: string, value2: string): string;
    	(value1: number, value2: number): string;
    };
    
    export default concat;

    index.test-d.ts

    import {expectType} from 'tsd';
    import concat from '.';
    
    expectType<string>(concat('foo', 'bar'));
    expectType<string>(concat(1, 2));
  7. Use the tsd Programmatic API

    main

    You can import tsd into your own test runner (like AVA or Jest) to retrieve diagnostics programmatically.

    import tsd, {formatter} from 'tsd';
    
    // Get raw diagnostics
    const diagnostics = await tsd();
    console.log(diagnostics.length);
    
    // Get formatted diagnostics matching CLI output
    const formattedDiagnostics = formatter(await tsd());

    tsd(options?) function

    Parameters:

    • cwd (string): Current working directory. Defaults to process.cwd().
    • typingsFile (string): Path to the type definition file. Defaults to the types property in package.json.
    • testFiles (string[]): An array of test file paths. Uses globby for discovery.
    import tsd from 'tsd';
    
    const diagnostics = await tsd();
    
    console.log(diagnostics.length);
    //=> 2
  8. Configure tsd via package.json or config file

    main

    You can configure tsd using a tsd key within your package.json or via a dedicated configuration object. The configuration requires a directory string and compilerOptions (which follow the standard TypeScript CompilerOptions schema).

    In package.json, the configuration follows this structure:

    {
      "tsd": {
        "directory": "path/to/typings",
        "compilerOptions": {
          "strict": true
        }
      }
    }
  9. Reference: tsd Assertions

    main

    The following functions are used within .test-d.ts files to perform type assertions:

    FunctionDescription
    expectType<T>(expression: T)Asserts that the type of expression is identical to type T
    expectNotType<T>(expression: any)Asserts that the type of expression is not identical to type T
    expectAssignable<T>(expression: T)Asserts that the type of expression is assignable to type T
    expectNotAssignable<T>(expression: any)Asserts that the type of expression is not assignable to type T
    expectError<T = any>(expression: T)Asserts that expression throws an error (ignores syntax errors)
    expectDeprecated(expression: any)Asserts that expression is marked as @deprecated
    expectNotDeprecated(expression: any)Asserts that expression is not marked as @deprecated
    printType(expression: any)Prints the type of expression as a warning (useful for debugging)
    expectNever(expression: never)Asserts that the type and return type of expression is never
    expectDocCommentIncludes<T>(expression: any)Asserts that the documentation comment of expression includes string literal type T
  10. Configure tsd via CLI flags

    main

    The tsd CLI provides the following flags for configuration:

    • --typings, -t: Path to the type definition file you want to test.
    • --files, -f: An array of specific test files with their paths.