From 446a7a081ea06032fc4f89d1afb1607d62c392e8 Mon Sep 17 00:00:00 2001 From: Forresst Date: Wed, 29 Jan 2020 18:35:58 +0100 Subject: [PATCH] Add `.asyncGenerator` and `.asyncGeneratorFunction` detection (#100) --- readme.md | 32 ++++++++++++++++++++++++++++++++ source/index.ts | 10 ++++++++++ test/test.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 12a4809..d274bb3 100644 --- a/readme.md +++ b/readme.md @@ -132,6 +132,38 @@ is.asyncFunction(() => {}); // => false ``` +##### .asyncGenerator(value) + +```js +is.asyncGenerator( + (async function * () { + yield 4; + })() +); +// => true + +is.asyncGenerator( + (function * () { + yield 4; + })() +); +// => false +``` + +##### .asyncGeneratorFunction(value) + +```js +is.asyncGeneratorFunction(async function * () { + yield 4; +}); +// => true + +is.asyncGeneratorFunction(function * () { + yield 4; +}); +// => false +``` + ##### .boundFunction(value) Returns `true` for any `bound` function. diff --git a/source/index.ts b/source/index.ts index 8eb85d2..4d42bfe 100644 --- a/source/index.ts +++ b/source/index.ts @@ -14,7 +14,9 @@ export const enum TypeName { symbol = 'symbol', Function = 'Function', Generator = 'Generator', + AsyncGenerator = 'AsyncGenerator', GeneratorFunction = 'GeneratorFunction', + AsyncGeneratorFunction = 'AsyncGeneratorFunction', AsyncFunction = 'AsyncFunction', Observable = 'Observable', Array = 'Array', @@ -141,6 +143,8 @@ is.asyncIterable = (value: unknown): value is AsyncIterableIterator is.generator = (value: unknown): value is Generator => is.iterable(value) && is.function_(value.next) && is.function_(value.throw); +is.asyncGenerator = (value: unknown): value is AsyncGenerator => is.asyncIterable(value) && is.function_(value.next) && is.function_(value.throw); + is.nativePromise = (value: unknown): value is Promise => isObjectOfType>(TypeName.Promise)(value); @@ -153,6 +157,8 @@ is.promise = (value: unknown): value is Promise => is.nativeProm is.generatorFunction = isObjectOfType(TypeName.GeneratorFunction); +is.asyncGeneratorFunction = (value: unknown): value is ((...args: any[]) => Promise) => getObjectType(value) === TypeName.AsyncGeneratorFunction; + is.asyncFunction = (value: unknown): value is ((...args: any[]) => Promise) => getObjectType(value) === TypeName.AsyncFunction; // eslint-disable-next-line no-prototype-builtins, @typescript-eslint/ban-types @@ -454,9 +460,11 @@ interface Assert { iterable: (value: unknown) => asserts value is Iterable; asyncIterable: (value: unknown) => asserts value is AsyncIterable; generator: (value: unknown) => asserts value is Generator; + asyncGenerator: (value: unknown) => asserts value is AsyncGenerator; nativePromise: (value: unknown) => asserts value is Promise; promise: (value: unknown) => asserts value is Promise; generatorFunction: (value: unknown) => asserts value is GeneratorFunction; + asyncGeneratorFunction: (value: unknown) => asserts value is AsyncGeneratorFunction; // eslint-disable-next-line @typescript-eslint/ban-types asyncFunction: (value: unknown) => asserts value is Function; // eslint-disable-next-line @typescript-eslint/ban-types @@ -542,9 +550,11 @@ export const assert: Assert = { iterable: (value: unknown): asserts value is Iterable => assertType(is.iterable(value), AssertionTypeDescription.iterable, value), asyncIterable: (value: unknown): asserts value is AsyncIterable => assertType(is.asyncIterable(value), AssertionTypeDescription.asyncIterable, value), generator: (value: unknown): asserts value is Generator => assertType(is.generator(value), TypeName.Generator, value), + asyncGenerator: (value: unknown): asserts value is AsyncGenerator => assertType(is.asyncGenerator(value), TypeName.AsyncGenerator, value), nativePromise: (value: unknown): asserts value is Promise => assertType(is.nativePromise(value), AssertionTypeDescription.nativePromise, value), promise: (value: unknown): asserts value is Promise => assertType(is.promise(value), TypeName.Promise, value), generatorFunction: (value: unknown): asserts value is GeneratorFunction => assertType(is.generatorFunction(value), TypeName.GeneratorFunction, value), + asyncGeneratorFunction: (value: unknown): asserts value is AsyncGeneratorFunction => assertType(is.asyncGeneratorFunction(value), TypeName.AsyncGeneratorFunction, value), // eslint-disable-next-line @typescript-eslint/ban-types asyncFunction: (value: unknown): asserts value is Function => assertType(is.asyncFunction(value), TypeName.AsyncFunction, value), // eslint-disable-next-line @typescript-eslint/ban-types diff --git a/test/test.ts b/test/test.ts index eb681bc..f48b7c3 100644 --- a/test/test.ts +++ b/test/test.ts @@ -156,7 +156,8 @@ const types = new Map([ function () {}, () => {}, async function () {}, - function * (): unknown {} + function * (): unknown {}, + async function * (): unknown {} ], typename: TypeName.Function }], @@ -232,6 +233,16 @@ const types = new Map([ ], typename: TypeName.Generator }], + ['asyncGenerator', { + is: is.asyncGenerator, + assert: assert.asyncGenerator, + fixtures: [ + (async function * () { + yield 4; + })() + ], + typename: TypeName.AsyncGenerator + }], ['generatorFunction', { is: is.generatorFunction, assert: assert.generatorFunction, @@ -243,6 +254,17 @@ const types = new Map([ typename: TypeName.Function, typeDescription: TypeName.GeneratorFunction }], + ['asyncGeneratorFunction', { + is: is.asyncGeneratorFunction, + assert: assert.asyncGeneratorFunction, + fixtures: [ + async function * () { + yield 4; + } + ], + typename: TypeName.Function, + typeDescription: TypeName.AsyncGeneratorFunction + }], ['asyncFunction', { is: is.asyncFunction, assert: assert.asyncFunction, @@ -609,7 +631,7 @@ test('is.array', t => { }); test('is.function', t => { - testType(t, 'function', ['generatorFunction', 'asyncFunction', 'boundFunction']); + testType(t, 'function', ['generatorFunction', 'asyncGeneratorFunction', 'asyncFunction', 'boundFunction']); }); test('is.boundFunction', t => { @@ -678,10 +700,33 @@ test('is.generator', t => { testType(t, 'generator'); }); +test('is.asyncGenerator', t => { + testType(t, 'asyncGenerator'); + + const fixture = (async function * () { + yield 4; + })(); + if (is.asyncGenerator(fixture)) { + t.true(is.function_(fixture.next)); + } +}); + test('is.generatorFunction', t => { testType(t, 'generatorFunction', ['function']); }); +test('is.asyncGeneratorFunction', t => { + testType(t, 'asyncGeneratorFunction', ['function']); + + const fixture = async function * () { + yield 4; + }; + + if (is.asyncGeneratorFunction(fixture)) { + t.true(is.function_(fixture().next)); + } +}); + test('is.map', t => { testType(t, 'map', ['emptyMap']); });