diff --git a/index.js b/index.js index 4fdd193..83b7a09 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,11 @@ * @typedef {null|undefined|TagName|TestFunctionAnything|Array.} Test */ +/** + * @template {Element} T + * @typedef {null|undefined|T['tagName']|TestFunctionPredicate|Array.>} PredicateTest + */ + /** * Check if an element passes a test * @@ -22,7 +27,7 @@ * * @template {Element} X * @callback TestFunctionPredicate - * @param {X} element + * @param {Element} element * @param {number|null|undefined} [index] * @param {Parent|null|undefined} [parent] * @returns {element is X} @@ -56,8 +61,9 @@ export const isElement = * When a `parent` node is known the `index` of node should also be given. * * @type {( - * ((node: unknown, test: T['tagName']|TestFunctionPredicate|Array.>, index?: number, parent?: Parent, context?: unknown) => node is T) & - * ((node?: unknown, test?: Test, index?: number, parent?: Parent, context?: unknown) => boolean) + * (() => false) & + * ((node: unknown, test?: PredicateTest, index?: number, parent?: Parent, context?: unknown) => node is T) & + * ((node: unknown, test: Test, index?: number, parent?: Parent, context?: unknown) => boolean) * )} */ ( diff --git a/index.test-d.ts b/index.test-d.ts index c8269fc..c9dd9f3 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -30,7 +30,7 @@ const article: Element = { const isSection = (element: Element): element is Section => element.tagName === 'section' -isElement() +expectType(isElement()) /* Missing parameters. */ expectError(isElement
()) @@ -133,3 +133,41 @@ convertElement() convertElement(null) convertElement(undefined) expectError(convertElement
()) + +declare const node: unknown + +/* Type assertion */ +if (isElement(node)) { + expectType(node) +} + +if (isElement(node, (node): node is Section => node.tagName === 'section')) { + expectType
(node) +} + +/** + * This test demonstrates that, while the test definitely asserts that `node` + * is an element, it asserts that it is *some* kind of element. + * If we’d define `node` as an `Element` in the if-branch (which is correct), + * TypeScript will think `node` is *not* an `Element` in the else-branch (which + * is incorrect). + * We can’t solve this in this project, but users can change their code (see + * next example). + */ +if (isElement(node, (node) => node.children.length > 0)) { + expectType(node) +} else { + expectType(node) +} + +/** + * This is the suggested use of this package so TypeScript can infer what types + * it’s working with. + * This way, `node` as an `Element` in the if-branch, and it could still be an + * element (or something else) in the else-branch. + */ +if (isElement(node) && node.children.length > 0) { + expectType(node) +} else { + expectType(node) +}