diff --git a/packages/core/src/graph-types.ts b/packages/core/src/graph-types.ts index 85736bb49..5d2f1127c 100644 --- a/packages/core/src/graph-types.ts +++ b/packages/core/src/graph-types.ts @@ -117,7 +117,10 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Node}, `false` otherwise. */ -function isNode (obj: object): obj is Node { +function isNode< + T extends NumberOrInteger = Integer, + P extends Properties = Properties, + Label extends string = string> (obj: unknown): obj is Node { return hasIdentifierProperty(obj, NODE_IDENTIFIER_PROPERTY) } @@ -228,7 +231,10 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Relationship}, `false` otherwise. */ -function isRelationship (obj: object): obj is Relationship { +function isRelationship< + T extends NumberOrInteger = Integer, + P extends Properties = Properties, + Type extends string = string> (obj: unknown): obj is Relationship { return hasIdentifierProperty(obj, RELATIONSHIP_IDENTIFIER_PROPERTY) } @@ -346,7 +352,10 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link UnboundRelationship}, `false` otherwise. */ -function isUnboundRelationship (obj: object): obj is UnboundRelationship { +function isUnboundRelationship< + T extends NumberOrInteger = Integer, + P extends Properties = Properties, + Type extends string = string> (obj: unknown): obj is UnboundRelationship { return hasIdentifierProperty(obj, UNBOUND_RELATIONSHIP_IDENTIFIER_PROPERTY) } @@ -394,7 +403,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link PathSegment}, `false` otherwise. */ -function isPathSegment (obj: object): obj is PathSegment { +function isPathSegment (obj: unknown): obj is PathSegment { return hasIdentifierProperty(obj, PATH_SEGMENT_IDENTIFIER_PROPERTY) } @@ -448,7 +457,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Path}, `false` otherwise. */ -function isPath (obj: object): obj is Path { +function isPath (obj: unknown): obj is Path { return hasIdentifierProperty(obj, PATH_IDENTIFIER_PROPERTY) } diff --git a/packages/core/src/spatial-types.ts b/packages/core/src/spatial-types.ts index 83d150a6f..1d3ff27f0 100644 --- a/packages/core/src/spatial-types.ts +++ b/packages/core/src/spatial-types.ts @@ -93,6 +93,7 @@ Object.defineProperty(Point.prototype, POINT_IDENTIFIER_PROPERTY, { * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Point}, `false` otherwise. */ -export function isPoint (obj?: any): obj is Point { - return obj != null && obj[POINT_IDENTIFIER_PROPERTY] === true +export function isPoint (obj: unknown): obj is Point { + const anyObj: any | null | undefined = obj + return obj != null && anyObj[POINT_IDENTIFIER_PROPERTY] === true } diff --git a/packages/core/src/temporal-types.ts b/packages/core/src/temporal-types.ts index 974f97c16..fb4632504 100644 --- a/packages/core/src/temporal-types.ts +++ b/packages/core/src/temporal-types.ts @@ -108,7 +108,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Duration}, `false` otherwise. */ -export function isDuration (obj: object): obj is Duration { +export function isDuration (obj: unknown): obj is Duration { return hasIdentifierProperty(obj, DURATION_IDENTIFIER_PROPERTY) } @@ -206,7 +206,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link LocalTime}, `false` otherwise. */ -export function isLocalTime (obj: object): boolean { +export function isLocalTime (obj: unknown): obj is LocalTime { return hasIdentifierProperty(obj, LOCAL_TIME_IDENTIFIER_PROPERTY) } @@ -315,7 +315,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Time}, `false` otherwise. */ -export function isTime (obj: object): obj is Time { +export function isTime (obj: unknown): obj is Time { return hasIdentifierProperty(obj, TIME_IDENTIFIER_PROPERTY) } @@ -399,7 +399,7 @@ Object.defineProperty( * @param {Object} obj - The object to test. * @return {boolean} `true` if given object is a {@link Date}, `false` otherwise. */ -export function isDate (obj: object): boolean { +export function isDate (obj: unknown): obj is Date { return hasIdentifierProperty(obj, DATE_IDENTIFIER_PROPERTY) } @@ -532,7 +532,7 @@ Object.defineProperty( * @param {Object} obj - The object to test. * @return {boolean} `true` if given object is a {@link LocalDateTime}, `false` otherwise. */ -export function isLocalDateTime (obj: any): obj is LocalDateTime { +export function isLocalDateTime (obj: unknown): obj is LocalDateTime { return hasIdentifierProperty(obj, LOCAL_DATE_TIME_IDENTIFIER_PROPERTY) } @@ -733,7 +733,7 @@ Object.defineProperty( * @param {Object} obj - The object to test. * @return {boolean} `true` if given object is a {@link DateTime}, `false` otherwise. */ -export function isDateTime (obj: object): boolean { +export function isDateTime (obj: unknown): obj is DateTime { return hasIdentifierProperty(obj, DATE_TIME_IDENTIFIER_PROPERTY) } diff --git a/packages/core/test/graph-types.test.ts b/packages/core/test/graph-types.test.ts index 527c44534..7b60fdc6f 100644 --- a/packages/core/test/graph-types.test.ts +++ b/packages/core/test/graph-types.test.ts @@ -22,7 +22,11 @@ import { Relationship, isRelationship, UnboundRelationship, - isUnboundRelationship + isUnboundRelationship, + Path, + PathSegment, + isPath, + isPathSegment } from '../src/graph-types' import { @@ -70,12 +74,30 @@ describe('Node', () => { expect(node.toString()).toMatchSnapshot() }) - test.each(validNodes())('should be consider a node', (node: any) => { + test.each(validNodes())('should be consider a node', (node: unknown) => { expect(isNode(node)).toBe(true) + + if (isNode(node)) { + const typedNode: Node = node + expect(typedNode).toEqual(node) + } else { + // @ts-expect-error + const typedNode: Node = node + expect(typedNode).toEqual(node) + } }) - test.each(nonNodes())('should not consider a non-node object as node', nonNode => { + test.each(nonNodes())('should not consider a non-node object as node', (nonNode: unknown) => { expect(isNode(nonNode)).toBe(false) + + if (isNode(nonNode)) { + const typedNode: Node = nonNode + expect(typedNode).toEqual(nonNode) + } else { + // @ts-expect-error + const typedNode: Node = nonNode + expect(typedNode).toEqual(nonNode) + } }) test('should type mapping labels', () => { @@ -219,6 +241,32 @@ describe('Relationship', () => { const _: 'DIRECTED' = a.type }) + test.each(validRelationships())('should be consider a relationship', (relationship: unknown) => { + expect(isRelationship(relationship)).toBe(true) + + if (isRelationship(relationship)) { + const typedRelationship: Relationship = relationship + expect(typedRelationship).toEqual(relationship) + } else { + // @ts-expect-error + const typedRelationship: Relationship = relationship + expect(typedRelationship).toEqual(relationship) + } + }) + + test.each(nonRelationships())('should not consider a non-relationship object as relationship', (nonRelationship: unknown) => { + expect(isRelationship(nonRelationship)).toBe(false) + + if (isRelationship(nonRelationship)) { + const typedRelationship: Relationship = nonRelationship + expect(typedRelationship).toEqual(nonRelationship) + } else { + // @ts-expect-error + const typedRelationship: Relationship = nonRelationship + expect(typedRelationship).toEqual(nonRelationship) + } + }) + function validRelationships (): any[] { return [ [new Relationship(1, 2, 3, 'Rel', {}, 'elementId', 'startNodeElementId', 'endNodeElementId')], @@ -346,6 +394,32 @@ describe('UnboundRelationship', () => { const _: 'DIRECTED' = a.type }) + test.each(validUnboundRelationships())('should be consider a unbound relationship', (unboundRelationship: unknown) => { + expect(isUnboundRelationship(unboundRelationship)).toBe(true) + + if (isUnboundRelationship(unboundRelationship)) { + const typedRelationship: UnboundRelationship = unboundRelationship + expect(typedRelationship).toEqual(unboundRelationship) + } else { + // @ts-expect-error + const typedRelationship: UnboundRelationship = unboundRelationship + expect(typedRelationship).toEqual(unboundRelationship) + } + }) + + test.each(nonUnboundRelationships())('should not consider a non-unbound relationship object as unbound relationship', (nonUnboundRelationship: unknown) => { + expect(isUnboundRelationship(nonUnboundRelationship)).toBe(false) + + if (isUnboundRelationship(nonUnboundRelationship)) { + const typedRelationship: UnboundRelationship = nonUnboundRelationship + expect(typedRelationship).toEqual(nonUnboundRelationship) + } else { + // @ts-expect-error + const typedRelationship: UnboundRelationship = nonUnboundRelationship + expect(typedRelationship).toEqual(nonUnboundRelationship) + } + }) + function validUnboundRelationships (): any[] { return [ [new UnboundRelationship(1, 'Rel', {}, 'elementId')], @@ -388,6 +462,111 @@ describe('UnboundRelationship', () => { } }) +describe('Path', () => { + test.each(validPaths())('should be consider a path', (path: unknown) => { + expect(isPath(path)).toBe(true) + + if (isPath(path)) { + const typed: Path = path + expect(typed).toEqual(path) + } else { + // @ts-expect-error + const typed: Path = path + expect(typed).toEqual(path) + } + }) + + test.each(nonPaths())('should not consider a non-path object as path', (nonPath: unknown) => { + expect(isPath(nonPath)).toBe(false) + + if (isPath(nonPath)) { + const typed: Path = nonPath + expect(typed).toEqual(nonPath) + } else { + // @ts-expect-error + const typed: Path = nonPath + expect(typed).toEqual(nonPath) + } + }) + + function validPaths (): any[] { + return [ + [new Path(new Node(1, [], {}), new Node(2, [], {}), [])], + [new Path(new Node(1, [], {}), new Node(2, [], {}), [new PathSegment(new Node(1, [], {}), new Relationship(1, 1, 2, 'type', {}), new Node(2, [], {}))])] + ] + } + + function nonPaths (): any[] { + return [ + [{ + start: new Node(1, [], {}), + end: new Node(2, [], {}), + length: 1, + segments: [ + new PathSegment( + new Node(1, [], {}), + new Relationship(1, 1, 2, 'type', {}), + new Node(2, [], {})) + ] + }], + [null], + [undefined], + [{}], + [1] + ] + } +}) + +describe('Path', () => { + test.each(validPathSegments())('should be consider a path segment', (pathSegment: unknown) => { + expect(isPathSegment(pathSegment)).toBe(true) + + if (isPathSegment(pathSegment)) { + const typed: PathSegment = pathSegment + expect(typed).toEqual(pathSegment) + } else { + // @ts-expect-error + const typed: PathSegment = pathSegment + expect(typed).toEqual(pathSegment) + } + }) + + test.each(nonPathSegments())('should not consider a non-path object as path segument', (nonPathSegment: unknown) => { + expect(isPathSegment(nonPathSegment)).toBe(false) + + if (isPathSegment(nonPathSegment)) { + const typed: PathSegment = nonPathSegment + expect(typed).toEqual(nonPathSegment) + } else { + // @ts-expect-error + const typed: PathSegment = nonPathSegment + expect(typed).toEqual(nonPathSegment) + } + }) + + function validPathSegments (): any[] { + return [ + [new PathSegment(new Node(1, [], {}), new Relationship(1, 1, 2, 'type', {}), new Node(2, [], {}))], + [new PathSegment(new Node(int(1), [], {}), new Relationship(int(1), int(1), int(2), 'type', {}), new Node(int(2), [], {}))] + ] + } + + function nonPathSegments (): any[] { + return [ + [{ + + start: new Node(1, [], {}), + end: new Node(2, [], {}), + relationship: new Relationship(1, 1, 2, 'type', {}) + }], + [null], + [undefined], + [{}], + [1] + ] + } +}) + function validIdentityAndExpectedElementIds (): any[] { return [ [10, '10'], diff --git a/packages/core/test/spatial-types.test.ts b/packages/core/test/spatial-types.test.ts index 977fc38be..791ba6d5e 100644 --- a/packages/core/test/spatial-types.test.ts +++ b/packages/core/test/spatial-types.test.ts @@ -94,14 +94,34 @@ describe('isPoint', () => { new Point(CARTESIAN_3D_CRS_CODE, 19.24, 100.29, 20.22222), new Point(CARTESIAN_3D_CRS_CODE, 19.24, 100.29), new Point(0, 19.24, 100.29, 20.22222) - ])('isPoint(%s) should be truthy', point => - expect(isPoint(point)).toBeTruthy() - ) + ])('isPoint(%s) should be true', (point: unknown) => { + expect(isPoint(point)).toBe(true) + + if (isPoint(point)) { + const typedPoint: Point = point + expect(typedPoint).toEqual(point) + } else { + // @ts-expect-error + const typedPoint: Point = point + expect(typedPoint).toEqual(point) + } + }) test.each([ { srid: CARTESIAN_3D_CRS_CODE, x: 18.24, y: 13.8, z: 124 }, { srid: 0, x: 18.24, y: 13.8 }, ['srid', CARTESIAN_3D_CRS_CODE, 'x', 18.24, 'y', 12.8, 'z', 124], 'Point(1, 2, 3, 4)' - ])('isPoint(%s) should be falsy', point => expect(isPoint(point)).toBeFalsy()) + ])('isPoint(%s) should be false', (point: unknown) => { + expect(isPoint(point)).toBe(false) + + if (isPoint(point)) { + const typedPoint: Point = point + expect(typedPoint).toEqual(point) + } else { + // @ts-expect-error + const typedPoint: Point = point + expect(typedPoint).toEqual(point) + } + }) }) diff --git a/packages/core/test/temporal-types.test.ts b/packages/core/test/temporal-types.test.ts index 6c41fe02b..6ea9c519a 100644 --- a/packages/core/test/temporal-types.test.ts +++ b/packages/core/test/temporal-types.test.ts @@ -18,7 +18,7 @@ */ import { StandardDate } from '../src/graph-types' -import { LocalDateTime, Date, DateTime } from '../src/temporal-types' +import { LocalDateTime, Date, DateTime, Duration, isDuration, LocalTime, isLocalTime, Time, isTime, isDate, isLocalDateTime, isDateTime } from '../src/temporal-types' import { temporalUtil } from '../src/internal' import fc from 'fast-check' @@ -166,6 +166,127 @@ describe('DateTime', () => { }) }) +describe('isDuration', () => { + it.each([ + [new Duration(1, 2, 3, 4), true], + [null, false], + [LocalDateTime.fromStandardDate(new global.Date()), false], + [{ months: 1, days: 1, seconds: 2, nanoseconds: 2 }, false] + ])('should be a type guard [%o]', (obj: unknown, objIsDuration: boolean) => { + expect(isDuration(obj)).toEqual(objIsDuration) + + if (isDuration(obj)) { + const duration: Duration = obj + expect(duration).toEqual(obj) + } else { + // @ts-expect-error + const duration: Duration = obj + expect(duration).toEqual(obj) + } + }) +}) + +describe('isLocalTime', () => { + it.each([ + [new LocalTime(1, 2, 3, 4), true], + [null, false], + [LocalDateTime.fromStandardDate(new global.Date()), false], + [{ months: 1, days: 1, seconds: 2, nanoseconds: 2 }, false] + ])('should be a type guard [%o]', (obj: unknown, objIsLocalTime: boolean) => { + expect(isLocalTime(obj)).toEqual(objIsLocalTime) + + if (isLocalTime(obj)) { + const localTime: LocalTime = obj + expect(localTime).toEqual(obj) + } else { + // @ts-expect-error + const localTime: LocalTime = obj + expect(localTime).toEqual(obj) + } + }) +}) + +describe('isTime', () => { + it.each([ + [new Time(1, 2, 3, 2, 300), true], + [null, false], + [LocalDateTime.fromStandardDate(new global.Date()), false], + [{ months: 1, days: 1, seconds: 2, nanoseconds: 2 }, false] + ])('should be a type guard [%o]', (obj: unknown, objIsTime: boolean) => { + expect(isTime(obj)).toEqual(objIsTime) + + if (isTime(obj)) { + const time: Time = obj + expect(time).toEqual(obj) + } else { + // @ts-expect-error + const time: Time = obj + expect(time).toEqual(obj) + } + }) +}) + +describe('isDate', () => { + it.each([ + [new Date(1, 2, 3), true], + [null, false], + [LocalDateTime.fromStandardDate(new global.Date()), false], + [{ months: 1, days: 1, seconds: 2, nanoseconds: 2 }, false] + ])('should be a type guard [%o]', (obj: unknown, objIsDate: boolean) => { + expect(isDate(obj)).toEqual(objIsDate) + + if (isDate(obj)) { + const date: Date = obj + expect(date).toEqual(obj) + } else { + // @ts-expect-error + const date: Date = obj + expect(date).toEqual(obj) + } + }) +}) + +describe('isLocalDateTime', () => { + it.each([ + [LocalDateTime.fromStandardDate(new global.Date()), true], + [new Date(1, 2, 3), false], + [null, false], + [{ months: 1, days: 1, seconds: 2, nanoseconds: 2 }, false] + ])('should be a type guard [%o]', (obj: unknown, objIsLocalDateTime: boolean) => { + expect(isLocalDateTime(obj)).toEqual(objIsLocalDateTime) + + if (isLocalDateTime(obj)) { + const localDateTime: LocalDateTime = obj + expect(localDateTime).toEqual(obj) + } else { + // @ts-expect-error + const localDateTime: LocalDateTime = obj + expect(localDateTime).toEqual(obj) + } + }) +}) + +describe('isDateTime', () => { + it.each([ + [DateTime.fromStandardDate(new global.Date()), true], + [new Date(1, 2, 3), false], + [null, false], + [1, false], + [{ months: 1, days: 1, seconds: 2, nanoseconds: 2 }, false] + ])('should be a type guard [%o]', (obj: unknown, objIsDateTime: boolean) => { + expect(isDateTime(obj)).toEqual(objIsDateTime) + + if (isDateTime(obj)) { + const dateTime: DateTime = obj + expect(dateTime).toEqual(obj) + } else { + // @ts-expect-error + const dateTime: DateTime = obj + expect(dateTime).toEqual(obj) + } + }) +}) + /** * The offset in StandardDate is the number of minutes * to sum to the date and time to get the UTC time. diff --git a/packages/neo4j-driver-deno/lib/core/graph-types.ts b/packages/neo4j-driver-deno/lib/core/graph-types.ts index 618732f70..75a95d035 100644 --- a/packages/neo4j-driver-deno/lib/core/graph-types.ts +++ b/packages/neo4j-driver-deno/lib/core/graph-types.ts @@ -117,7 +117,10 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Node}, `false` otherwise. */ -function isNode (obj: object): obj is Node { +function isNode< + T extends NumberOrInteger = Integer, + P extends Properties = Properties, + Label extends string = string> (obj: unknown): obj is Node { return hasIdentifierProperty(obj, NODE_IDENTIFIER_PROPERTY) } @@ -228,7 +231,10 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Relationship}, `false` otherwise. */ -function isRelationship (obj: object): obj is Relationship { +function isRelationship< + T extends NumberOrInteger = Integer, + P extends Properties = Properties, + Type extends string = string> (obj: unknown): obj is Relationship { return hasIdentifierProperty(obj, RELATIONSHIP_IDENTIFIER_PROPERTY) } @@ -346,7 +352,10 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link UnboundRelationship}, `false` otherwise. */ -function isUnboundRelationship (obj: object): obj is UnboundRelationship { +function isUnboundRelationship< + T extends NumberOrInteger = Integer, + P extends Properties = Properties, + Type extends string = string> (obj: unknown): obj is UnboundRelationship { return hasIdentifierProperty(obj, UNBOUND_RELATIONSHIP_IDENTIFIER_PROPERTY) } @@ -394,7 +403,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link PathSegment}, `false` otherwise. */ -function isPathSegment (obj: object): obj is PathSegment { +function isPathSegment (obj: unknown): obj is PathSegment { return hasIdentifierProperty(obj, PATH_SEGMENT_IDENTIFIER_PROPERTY) } @@ -448,7 +457,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Path}, `false` otherwise. */ -function isPath (obj: object): obj is Path { +function isPath (obj: unknown): obj is Path { return hasIdentifierProperty(obj, PATH_IDENTIFIER_PROPERTY) } diff --git a/packages/neo4j-driver-deno/lib/core/spatial-types.ts b/packages/neo4j-driver-deno/lib/core/spatial-types.ts index f0911dafc..4a7a05f93 100644 --- a/packages/neo4j-driver-deno/lib/core/spatial-types.ts +++ b/packages/neo4j-driver-deno/lib/core/spatial-types.ts @@ -93,6 +93,7 @@ Object.defineProperty(Point.prototype, POINT_IDENTIFIER_PROPERTY, { * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Point}, `false` otherwise. */ -export function isPoint (obj?: any): obj is Point { - return obj != null && obj[POINT_IDENTIFIER_PROPERTY] === true +export function isPoint (obj: unknown): obj is Point { + const anyObj: any | null | undefined = obj + return obj != null && anyObj[POINT_IDENTIFIER_PROPERTY] === true } diff --git a/packages/neo4j-driver-deno/lib/core/temporal-types.ts b/packages/neo4j-driver-deno/lib/core/temporal-types.ts index 7e79de0a2..abbe1fb1e 100644 --- a/packages/neo4j-driver-deno/lib/core/temporal-types.ts +++ b/packages/neo4j-driver-deno/lib/core/temporal-types.ts @@ -108,7 +108,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Duration}, `false` otherwise. */ -export function isDuration (obj: object): obj is Duration { +export function isDuration (obj: unknown): obj is Duration { return hasIdentifierProperty(obj, DURATION_IDENTIFIER_PROPERTY) } @@ -206,7 +206,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link LocalTime}, `false` otherwise. */ -export function isLocalTime (obj: object): boolean { +export function isLocalTime (obj: unknown): obj is LocalTime { return hasIdentifierProperty(obj, LOCAL_TIME_IDENTIFIER_PROPERTY) } @@ -315,7 +315,7 @@ Object.defineProperty( * @param {Object} obj the object to test. * @return {boolean} `true` if given object is a {@link Time}, `false` otherwise. */ -export function isTime (obj: object): obj is Time { +export function isTime (obj: unknown): obj is Time { return hasIdentifierProperty(obj, TIME_IDENTIFIER_PROPERTY) } @@ -399,7 +399,7 @@ Object.defineProperty( * @param {Object} obj - The object to test. * @return {boolean} `true` if given object is a {@link Date}, `false` otherwise. */ -export function isDate (obj: object): boolean { +export function isDate (obj: unknown): obj is Date { return hasIdentifierProperty(obj, DATE_IDENTIFIER_PROPERTY) } @@ -532,7 +532,7 @@ Object.defineProperty( * @param {Object} obj - The object to test. * @return {boolean} `true` if given object is a {@link LocalDateTime}, `false` otherwise. */ -export function isLocalDateTime (obj: any): obj is LocalDateTime { +export function isLocalDateTime (obj: unknown): obj is LocalDateTime { return hasIdentifierProperty(obj, LOCAL_DATE_TIME_IDENTIFIER_PROPERTY) } @@ -733,7 +733,7 @@ Object.defineProperty( * @param {Object} obj - The object to test. * @return {boolean} `true` if given object is a {@link DateTime}, `false` otherwise. */ -export function isDateTime (obj: object): boolean { +export function isDateTime (obj: unknown): obj is DateTime { return hasIdentifierProperty(obj, DATE_TIME_IDENTIFIER_PROPERTY) }