Skip to content

Commit

Permalink
feat(Typescript): Add isType type guard
Browse files Browse the repository at this point in the history
  • Loading branch information
nokome committed Jul 31, 2019
1 parent 9096d5f commit ed8fb4a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 12 deletions.
42 changes: 31 additions & 11 deletions ts/util/__tests__/guards.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
isPrimitive,
typeIs,
nodeIs,
isa
isA,
isType
} from '../guards'

const primitives = [null, true, false, NaN, 2, 'string']
Expand Down Expand Up @@ -56,28 +57,47 @@ describe('nodeIs', () => {
expect(nodeIs(typeMap)({ type: typeMap.someType })).toBe(true))
})

describe('isa', () => {
describe('isA', () => {
const person = { type: 'Person' }
const para = { type: 'Paragraph', content: [] }

test('it returns false for undefined types', () => {
// This is a compile error too
// @ts-ignore
expect(isa(person, 'Foo')).toBe(false)
expect(isA(person, 'Foo')).toBe(false)
})

test('it returns true for the right type', () => {
expect(isa(person, 'Person')).toBe(true)
expect(isa(para, 'Paragraph')).toBe(true)
expect(isA(person, 'Person')).toBe(true)
expect(isA(para, 'Paragraph')).toBe(true)
})

test('it returns false for the wrong type', () => {
expect(isa(para, 'Person')).toBe(false)
expect(isa(null, 'Person')).toBe(false)
expect(isa(true, 'Person')).toBe(false)
expect(isa(1.0, 'Person')).toBe(false)
expect(isa([], 'Person')).toBe(false)
expect(isa({ type: 'Foo' }, 'Person')).toBe(false)
expect(isA(para, 'Person')).toBe(false)
expect(isA(null, 'Person')).toBe(false)
expect(isA(true, 'Person')).toBe(false)
expect(isA(1.0, 'Person')).toBe(false)
expect(isA([], 'Person')).toBe(false)
expect(isA({ type: 'Foo' }, 'Person')).toBe(false)
})
})

describe('isType', () => {
const person = { type: 'Person' }
const para = { type: 'Paragraph', content: [] }

test('it returns false for undefined types', () => {
// This is a compile error too
// @ts-ignore
expect(isType('Foo')(person)).toBe(false)
})

test('it returns true for the right type', () => {
expect(isType('Person')(person)).toBe(true)
})

test('it returns false for the wrong type', () => {
expect(isType('Person')(para)).toBe(false)
})
})

Expand Down
19 changes: 18 additions & 1 deletion ts/util/guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ export const is = <Ts extends Entity>(type: keyof TypeMap<Ts>) => {
}

/**
* A type guard to determine whether a node is of a particular type.
* A type guard to determine whether a node is of a specific type.
* Returns a boolean value and narrows the TypeScript inferred type to
* the type.
*
* e.g. `isA(node, 'Paragraph')`
*
* @param type The type to test for
*/
export const isA = <K extends keyof Types>(
Expand All @@ -78,6 +80,21 @@ export const isA = <K extends keyof Types>(
return isEntity(node) && node.type === type
}

/**
* Returns a type guard to determine whether a node is of a specific type.
* Returns a boolean value and narrows the TypeScript inferred type to
* the type.
*
* e.g. `article.content.filter(isType('Paragraph'))`
*
* @param type The type to test for
*/
export const isType = <K extends keyof Types>(type: K) => (
node?: Node
): node is Types[K] => {
return node !== undefined && isA(node, type)
}

/**
* Type guard to determine whether a node is a primitive type.
* Returns a boolean value and narrows the TypeScript inferred type.
Expand Down

0 comments on commit ed8fb4a

Please sign in to comment.