Skip to content

Commit

Permalink
Turn assertions into type guards
Browse files Browse the repository at this point in the history
Update the `deepEqual`, `like`, `false`, `true` and `is` assertions so
they can be used as type guards. Fixes #2456.

Change the `deepEqual`, `like` and `is` assertions so the actual and
expected parameters can be typed separately. Fixes #2580.
  • Loading branch information
novemberborn committed Mar 7, 2021
1 parent 72a4e2f commit 5eea608
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 7 deletions.
14 changes: 7 additions & 7 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export interface DeepEqualAssertion {
* Assert that `actual` is [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to
* `expected`, returning a boolean indicating whether the assertion passed.
*/
<ValueType = any>(actual: ValueType, expected: ValueType, message?: string): boolean;
<Actual, Expected extends Actual>(actual: Actual, expected: Expected, message?: string): actual is Expected;

/** Skip this assertion. */
skip(actual: any, expected: any, message?: string): void;
Expand All @@ -160,7 +160,7 @@ export interface LikeAssertion {
/**
* Assert that `value` is like `selector`, returning a boolean indicating whether the assertion passed.
*/
(value: any, selector: Record<string, any>, message?: string): boolean;
<Expected extends Record<string, any>>(value: any, selector: Expected, message?: string): value is Expected;

/** Skip this assertion. */
skip(value: any, selector: any, message?: string): void;
Expand All @@ -178,7 +178,7 @@ export interface FalseAssertion {
/**
* Assert that `actual` is strictly false, returning a boolean indicating whether the assertion passed.
*/
(actual: any, message?: string): boolean;
(actual: any, message?: string): actual is false;

/** Skip this assertion. */
skip(actual: any, message?: string): void;
Expand All @@ -201,7 +201,7 @@ export interface IsAssertion {
* value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`,
* returning a boolean indicating whether the assertion passed.
*/
<ValueType = any>(actual: ValueType, expected: ValueType, message?: string): boolean;
<Actual, Expected extends Actual>(actual: Actual, expected: Expected, message?: string): actual is Expected;

/** Skip this assertion. */
skip(actual: any, expected: any, message?: string): void;
Expand All @@ -213,7 +213,7 @@ export interface NotAssertion {
* value](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) as `expected`,
* returning a boolean indicating whether the assertion passed.
*/
<ValueType = any>(actual: ValueType, expected: ValueType, message?: string): boolean;
<Actual, Expected>(actual: Actual, expected: Expected, message?: string): boolean;

/** Skip this assertion. */
skip(actual: any, expected: any, message?: string): void;
Expand All @@ -224,7 +224,7 @@ export interface NotDeepEqualAssertion {
* Assert that `actual` is not [deeply equal](https://github.com/concordancejs/concordance#comparison-details) to
* `expected`, returning a boolean indicating whether the assertion passed.
*/
<ValueType = any>(actual: ValueType, expected: ValueType, message?: string): boolean;
<Actual, Expected>(actual: Actual, expected: Expected, message?: string): boolean;

/** Skip this assertion. */
skip(actual: any, expected: any, message?: string): void;
Expand Down Expand Up @@ -334,7 +334,7 @@ export interface TrueAssertion {
/**
* Assert that `actual` is strictly true, returning a boolean indicating whether the assertion passed.
*/
(actual: any, message?: string): boolean;
(actual: any, message?: string): actual is true;

/** Skip this assertion. */
skip(actual: any, message?: string): void;
Expand Down
40 changes: 40 additions & 0 deletions test-d/assertions-as-type-guards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {expectType} from 'tsd';
import test from '..';

type Expected = {foo: 'bar'};
const expected: Expected = {foo: 'bar'};

test('deepEqual', t => {
const actual: unknown = {};
if (t.deepEqual(actual, expected)) {
expectType<Expected>(actual);
}
});

test('like', t => {
const actual: unknown = {};
if (t.like(actual, expected)) {
expectType<Expected>(actual);
}
});

test('is', t => {
const actual: unknown = 2;
if (t.is(actual, 3 as const)) {
expectType<3>(actual);
}
});

test('false', t => {
const actual: unknown = true;
if (t.false(actual)) {
expectType<false>(actual);
}
});

test('true', t => {
const actual: unknown = false;
if (t.true(actual)) {
expectType<true>(actual);
}
});

0 comments on commit 5eea608

Please sign in to comment.