Skip to content

Commit

Permalink
Make assert, truthy and falsy typeguards
Browse files Browse the repository at this point in the history
  • Loading branch information
ZachHaber committed Aug 14, 2023
1 parent e58f466 commit f106e37
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
28 changes: 28 additions & 0 deletions test-types/import-in-cts/assertions-as-type-guards.cts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import {expectType} from 'tsd';
type Expected = {foo: 'bar'};
const expected: Expected = {foo: 'bar'};

test('assert', t => {
const actual = expected as Expected | undefined;
if (t.truthy(actual)) {
expectType<Expected>(actual);
} else {
expectType<undefined>(actual);
}
});

test('deepEqual', t => {
const actual: unknown = {};
if (t.deepEqual(actual, expected)) {
Expand Down Expand Up @@ -32,9 +41,28 @@ test('false', t => {
}
});

test('falsy', t => {
type Actual = Expected | undefined | null | false | 0 | '' | 0n;
const actual = undefined as Actual;
if (t.falsy(actual)) {
expectType<Exclude<Actual, Expected>>(actual);
} else {
expectType<Expected>(actual);
}
});

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

test('truthy', t => {
const actual = expected as Expected | undefined;
if (t.truthy(actual)) {
expectType<Expected>(actual);
} else {
expectType<undefined>(actual);
}
});
28 changes: 28 additions & 0 deletions test-types/module/assertions-as-type-guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import test from '../../entrypoints/main.mjs';
type Expected = {foo: 'bar'};
const expected: Expected = {foo: 'bar'};

test('assert', t => {
const actual = expected as Expected | undefined;
if (t.truthy(actual)) {
expectType<Expected>(actual);
} else {
expectType<undefined>(actual);
}
});

test('deepEqual', t => {
const actual: unknown = {};
if (t.deepEqual(actual, expected)) {
Expand Down Expand Up @@ -33,9 +42,28 @@ test('false', t => {
}
});

test('falsy', t => {
type Actual = Expected | undefined | null | false | 0 | '' | 0n;

Check failure on line 46 in test-types/module/assertions-as-type-guards.ts

View workflow job for this annotation

GitHub Actions / Lint source files

Don't use `null` as a type. Use `undefined` instead. See: https://github.com/sindresorhus/meta/issues/7
const actual = undefined as Actual;
if (t.falsy(actual)) {
expectType<Exclude<Actual, Expected>>(actual);
} else {
expectType<Expected>(actual);
}
});

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

test('truthy', t => {
const actual = expected as Expected | undefined;
if (t.truthy(actual)) {
expectType<Expected>(actual);
} else {
expectType<undefined>(actual);
}
});
8 changes: 5 additions & 3 deletions types/assertions.d.cts
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,14 @@ export type Assertions = {
truthy: TruthyAssertion;
};

type Falsy = false | 0 | -0 | 0n | '' | null | undefined;

export type AssertAssertion = {
/**
* Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean
* indicating whether the assertion passed.
*/
(actual: any, message?: string): boolean;
<T>(actual: T, message?: string): actual is Exclude<T, Falsy>;

/** Skip this assertion. */
skip(actual: any, message?: string): void;
Expand Down Expand Up @@ -192,7 +194,7 @@ export type FalsyAssertion = {
* Assert that `actual` is [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy), returning a boolean
* indicating whether the assertion passed.
*/
(actual: any, message?: string): boolean;
<T>(actual: T, message?: string): actual is T extends Falsy ? T :never;

/** Skip this assertion. */
skip(actual: any, message?: string): void;
Expand Down Expand Up @@ -337,7 +339,7 @@ export type TruthyAssertion = {
* Assert that `actual` is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), returning a boolean
* indicating whether the assertion passed.
*/
(actual: any, message?: string): boolean;
<T>(actual: T, message?: string): actual is Exclude<T, Falsy>;

/** Skip this assertion. */
skip(actual: any, message?: string): void;
Expand Down

0 comments on commit f106e37

Please sign in to comment.