Skip to content

feat: add built-in model property types typdef #1902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ export * from './types/observer-mixin';
export * from './types/validation-mixin';
export * from './types/inclusion-mixin';
export * from './types/connector';
export * from './types/geo';
12 changes: 12 additions & 0 deletions types/__tests__/date-string.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { inspect } from 'util';
import {DateString} from '../date-string';

let stringTypeGuard: string;

const dateString = new DateString('2020-01-01');
DateString('2020-01-01');
DateString(dateString);
stringTypeGuard = dateString.toJSON().when;
stringTypeGuard = dateString.toString();
stringTypeGuard = dateString.inspect();
stringTypeGuard = dateString[inspect.custom]();
25 changes: 25 additions & 0 deletions types/__tests__/geopoint.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {GeoDistanceUnit, GeoPoint, filter, nearFilter} from '../geo';

let numberTypeGuard: number;

new GeoPoint(123, 456);
new GeoPoint('123', 456);
new GeoPoint(123, '456');
new GeoPoint('123', '456');

new GeoPoint([123, 456]);
new GeoPoint(['123', '456']);
new GeoPoint(['123', 456]);
new GeoPoint([123, '456']);

new GeoPoint({lat: 123, lng: 456});
new GeoPoint({lat: '123', lng: 456})
new GeoPoint({lat: 123, lng: '456'})
new GeoPoint({lat: '123', lng: '456'});

numberTypeGuard = GeoPoint.distanceBetwen([123, 456], [123, 456]);
numberTypeGuard = GeoPoint.distanceBetwen([123, 456], [123, 456], {type: GeoDistanceUnit.degrees});

const geoPoint = new GeoPoint(123, 456);
numberTypeGuard = geoPoint.distanceTo([123, 456])
numberTypeGuard = geoPoint.distanceTo([123, 456], {type: GeoDistanceUnit.degrees});
15 changes: 15 additions & 0 deletions types/__tests__/types.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as buildModelTypes from '../types';
import {ModelTypes, Type, Types} from '../types';

let stringTypeGuard: string;
let voidTypeGuard: void;
let jsonTypeGuard: Types.JSON;

stringTypeGuard = Types.JSON('arbitrary value');
voidTypeGuard = Types.JSON(new Types.JSON('test'));
jsonTypeGuard = new Types.JSON('test');
const modelTypes: ModelTypes = {}
buildModelTypes(modelTypes);
voidTypeGuard = modelTypes.registerType({} as Type);
voidTypeGuard = modelTypes.registerType({} as Type, ['custom name 1']);
modelTypes.schemaTypes;
21 changes: 21 additions & 0 deletions types/date-string.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {inspect} from 'util';

// @achrinza: One of the limitations of these definitions is that the class instance
// isn't callable; Hence, changing the `value` class member must be done
// directly. This is a TypeScript limitation as class constructors cannot
// have a custom return value.
export function DateString(value: DateString | string): DateString;
export class DateString {
private _when: string;
private _date: Date;

get when(): string;
set when(val: string);

constructor(value: string);

toString(): DateString['when'];
toJSON(): {when: DateString['when']};
inspect(): string;
[inspect.custom]: DateString['inspect'];
}
122 changes: 122 additions & 0 deletions types/geo.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Where } from "./query";

export function nearFilter(where: Where): false | GeoPointFilter[];

export function filter(rawResults: GeoPointRawResult[], filters: GeoPointFilter[]): GeoPointFilter;

export type GeoPointFilter = {
near: GeoPoint | ConstructorParameters<typeof GeoPoint>;
maxDistance: number;
minDistance: number;
unit: GeoDistanceUnit;
mongoKey: string;
key: string;
}

export type GeoPointRawResult = {
[key: string]: {
lat: number;
lng: number;
}
}

export class GeoPoint {
lat: number;
lng: number;

/**
*
* @example
* ```typescript
* new GeoPoint({
* lat: 145,
* lng: 96,
* });
* ```
*
* @example
* ```typescript
* new GeoPoint({
* lat: '145',
* lng: '96',
* });
* ```
*
* @param data
*/
constructor(data: {
lat: string | number,
lng: string | number,
})

/**
* @example
* ```typescript
* new GeoPoint('145,96');
* ```
*
* @example
* ```typescript
* new GeoPoint('145 , 96');
* ```
*
* @param data
*/
constructor(data: `${number},${number}`)

/**
* @example
* ```typescript
* new GeoPoint([145, 96]);
* ```
*
* @example
* ```typescript
* new GeoPoint(['145', '96']);
* ```
*
* @param data
*/
constructor(data: [string | number, string | number])

/**
* @example
* ```typescript
* new GeoPoint(145, 96);
* ```
*
* @example
* ```typescript
* new GeoPoint('145', '96');
* ```
*
* @param data
*/
constructor(lat: string | number, lng: string | number)

static distanceBetwen(
a: GeoPoint | ConstructorParameters<typeof GeoPoint>,
b: GeoPoint | ConstructorParameters<typeof GeoPoint>,
options?: GeoDistanceOptions,
): number;

distanceTo(
point: GeoPoint | ConstructorParameters<typeof GeoPoint>,
options?: GeoDistanceOptions,
): number;

toString(): `$${number},${number}`;
}

export type GeoDistanceOptions = {
type: GeoDistanceUnit;
}

export enum GeoDistanceUnit {
'kilometers',
'meters',
'miles',
'feet',
'radians',
'degrees',
}
66 changes: 66 additions & 0 deletions types/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {DateString} from './date-string';
import {GeoPoint} from './geo';

// @achrinza: The return value is a hack to inform TypeScript of function parameter mutations.
// see: https://github.com/microsoft/TypeScript/issues/22865#issuecomment-725015710
declare function registerModelTypes(modelTypes: registerModelTypes.ModelTypes): asserts modelTypes is registerModelTypes.BuiltModelTypes;

declare namespace registerModelTypes {
// @achrinza: One of the limitations of these definitions is that the class instance
// isn't callable; Hence, changing the `value` class member must be done
// directly. This is a TypeScript limitation as class constructors cannot
// have a custom return value.
namespace Types {
function Text<T extends unknown>(value: T): T extends Text ? void : T;
class Text implements Type {
value: Text;
constructor(value: Text);
toJSON(): Text;
toObject(): Text;
}

function JSON<T extends unknown>(value: T): T extends JSON ? void : T;
class JSON implements Type {
value: unknown;
constructor(value: unknown)
toJSON(): unknown;
toObject(): unknown;
}


function Any<T extends unknown>(value: T): T extends Any ? void : T;
class Any implements Type {
value: unknown;
constructor(value: unknown);
toJSON(): unknown;
toObject(): unknown;
}
}

interface ModelTypes {
[type: string]: Type | unknown;
}

interface Type {
value: unknown;
toJSON(): unknown;
toObject(): unknown;
}

interface BuiltModelTypes extends ModelTypes {
schemaTypes: Record<string, Type> & {
'String': String;
'Number': Number;
'Date': Date
'DateString': DateString
'Binary': Buffer;
'Buffer': Buffer;
'Array': Array<unknown>;
'Object': Object;
'GeoPoint': GeoPoint
};
registerType: (type: Type, names?: string[]) => void;
}

}
export = registerModelTypes;