diff --git a/tsconfig.json b/tsconfig.json index df49bce7..c726358e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,17 @@ { "compilerOptions": { "emitDeclarationOnly": true, - "declaration": true - } + "declaration": true, + }, + "include": [ + // only compile the type definitions by default. + // That is, ignore the files in 'examples/**' + "types/**.d.ts" + ], + "exclude": [ + // Among the type definitions, don't try to compile + // the test file which implements bad types. + // It implements bad types for testing purposes. + "types/index.test-d.ts" + ] } diff --git a/types/chain.d.ts b/types/chain.d.ts index 8ed085f8..fe9e2cee 100644 --- a/types/chain.d.ts +++ b/types/chain.d.ts @@ -1,4 +1,4 @@ -import { AlwaysDisallowedType, DisallowPrimitives, DisallowArray, AckCallback, ArrayOf, ArrayAsRecord, Saveable, IGunCryptoKeyPair } from './types'; +import { AlwaysDisallowedType, DisallowPrimitives, AckCallback, Saveable, IGunCryptoKeyPair } from './types'; import { IGunConstructorOptions } from './options'; declare type ITSResolvable = R | PromiseLike; @@ -19,33 +19,47 @@ export interface IGunChainReference, ReferenceKey * @param callback invoked on each acknowledgment * @param options additional options (used for specifying certs) */ - put(data: Partial>>>, callback?: AckCallback | null, options?: { opt?: { cert?: string } }): IGunChainReference; + put(data: Partial>>, callback?: AckCallback | null, options?: { opt?: { cert?: string } }): IGunChainReference; /** - * Where to read data from. - * @param key The key is the ID or property name of the data that you saved from earlier - * (or that will be saved later). - * * Note that if you use .put at any depth after a get it first reads the data and then writes, merging the data as a partial update. - * @param callback You will usually be using gun.on or gun.once to actually retrieve your data, - * not this callback (it is intended for more low level control, for module and extensions). + * **.set does not means 'set data', it means a Mathematical Set** * - * **Avoid use callback. The type in the document may be wrong.** + * Add a unique item to an unordered list. + * `gun.set` works like a mathematical set, where each item in the list is unique. + * If the item is added twice, it will be merged. * - * **Here the type of callback respect to the actual behavior** + * **This means only objects, for now, are supported.** + * @param data the object to add to the set + * @param callback optional function to invoke when the operation is complete + * @param options additional options (used for specifying certs) */ - get(key: ArrayOf extends never ? K : ArrayOf, callback?: ( + set(data: Partial>>, callback?: AckCallback | null, options?: { opt?: { cert?: string } }): IGunChainReference; + + /** + * Where to read data from. + * @param key The key is the ID or property name of the data that you saved from earlier + * (or that will be saved later). + * * Note that if you use .put at any depth after a get it first reads the data and then writes, merging the data as a partial update. + * @param callback You will usually be using gun.on or gun.once to actually retrieve your data, + * not this callback (it is intended for more low level control, for module and extensions). + * + * **Avoid use callback. The type in the document may be wrong.** + * + * **Here the type of callback respect to the actual behavior** + */ + get(key: Exclude>, callback?: ( /** the raw data. Internal node of gun. Will not typed here. */ paramA: Record<'gun' | '$' | 'root' | 'id' | 'back' | 'on' | 'tag' | 'get' | 'soul' | 'ack' | 'put', any>, /** the key, ID, or property name of the data. */ paramB: Record<'off' | 'to' | 'next' | 'the' | 'on' | 'as' | 'back' | 'rid' | 'id', any>) => void): IGunChainReference; /** - * Change the configuration of the gun database instance. - * @param options The options argument is the same object you pass to the constructor. - * - * The options's properties replace those in the instance's configuration but options.peers are **added** to peers known to the gun instance. - * @returns No mention in the document, behavior as `ChainReference` - */ + * Change the configuration of the gun database instance. + * @param options The options argument is the same object you pass to the constructor. + * + * The options's properties replace those in the instance's configuration but options.peers are **added** to peers known to the gun instance. + * @returns No mention in the document, behavior as `ChainReference` + */ opt(options: IGunConstructorOptions): IGunChainReference; /** @@ -69,7 +83,7 @@ export interface IGunChainReference, ReferenceKey * Since gun streams data, the callback will probably be called multiple times as new chunk comes in. * To remove a listener call .off() on the same property or node. */ - on(callback: (data: DisallowPrimitives>>, key: ReferenceKey) => void, option?: { + on(callback: (data: DisallowPrimitives>, key: ReferenceKey) => void, option?: { change: boolean; } | boolean): IGunChainReference; @@ -77,33 +91,16 @@ export interface IGunChainReference, ReferenceKey * Get the current data without subscribing to updates. Or `undefined` if it cannot be found. * @returns In the document, it said the return value may change in the future. Don't rely on it. */ - once(callback?: (data: (DisallowPrimitives>>) | undefined, key: ReferenceKey) => void, option?: { + once(callback?: (data: (DisallowPrimitives>>) | undefined, key: ReferenceKey) => void, option?: { wait: number; }): IGunChainReference; - /** - * **.set does not means 'set data', it means a Mathematical Set** - * - * Add a unique item to an unordered list. - * `gun.set` works like a mathematical set, where each item in the list is unique. - * If the item is added twice, it will be merged. - * - * **This means only objects, for now, are supported.** - * @param data the object to add to the set - * @param callback optional function to invoke when the operation is complete - * @param options additional options (used for specifying certs) - */ - set(data: AlwaysDisallowedType ? U extends { - [key: string]: any; - [key: number]: any; - } ? ArrayOf : never : never>, callback?: AckCallback | null, options?: { opt?: { cert?: string } }): IGunChainReference>; - /** * Map iterates over each property and item on a node, passing it down the chain, * behaving like a forEach on your data. * It also subscribes to every item as well and listens for newly inserted items. */ - map(callback?: (value: ArrayOf, key: DataType) => ArrayOf | undefined): IGunChainReference, ReferenceKey>; + map(callback?: (value: DataType, key: string) => DataType | undefined): IGunChainReference; /** * Undocumented, but extremely useful and mentioned in the document @@ -139,7 +136,7 @@ export interface IGunChainReference, ReferenceKey * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/open.js')` or * ``! */ - open?(callback: (data: ArrayAsRecord) => void): IGunChainReference; + open?(callback: (data: DataType) => void): IGunChainReference; /** * Loads the full object once. It is the same as `open` but with the behavior of `once`. @@ -147,7 +144,7 @@ export interface IGunChainReference, ReferenceKey * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/load.js')` or * ``! */ - load?(callback: (data: ArrayAsRecord) => void): IGunChainReference; + load?(callback: (data: DataType) => void): IGunChainReference; /** * Returns a promise for you to use. @@ -155,8 +152,8 @@ export interface IGunChainReference, ReferenceKey * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/then.js')` or * ``! */ - then?>(onfulfilled: (value: TResult1) => ITSResolvable): Promise; - then?>(): Promise; + // then?(onfulfilled: (value: TResult1) => ITSResolvable): Promise; + // then?(): Promise; /** * Returns a promise for you to use. @@ -165,12 +162,12 @@ export interface IGunChainReference, ReferenceKey * ``! */ promise?; + put: Record; key: ReferenceKey; gun: IGunChainReference; }>(onfulfilled: (value: TResult1) => ITSResolvable): Promise; promise?; + put: Record; key: ReferenceKey; gun: IGunChainReference; }>(): Promise; @@ -184,7 +181,7 @@ export interface IGunChainReference, ReferenceKey * ``! */ bye?(): { - put(data: DisallowArray>): void; + put(data: Saveable): void; }; /** @@ -194,7 +191,7 @@ export interface IGunChainReference, ReferenceKey * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/later.js')` or * ``! */ - later?(callback: (this: IGunChainReference, data: ArrayAsRecord, key: ReferenceKey) => void, seconds: number): IGunChainReference; + later?(callback: (this: IGunChainReference, data: Record, key: ReferenceKey) => void, seconds: number): IGunChainReference; /** * After you save some data in an unordered list, you may need to remove it. @@ -202,17 +199,17 @@ export interface IGunChainReference, ReferenceKey * **Warning**: Not included by default! You must include it yourself via `require('gun/lib/unset.js')` or * ``! */ - unset?(data: ArrayOf): IGunChainReference; + unset?(data: K): IGunChainReference; /** * Subscribes to all future events that occur on the Timegraph and retrieve a specified number of old events * * **Warning**: The Timegraph extension isn't required by default, you would need to include at "gun/lib/time.js" */ - time?(callback: (data: ArrayOf, key: ReferenceKey, time: number) => void, alsoReceiveNOldEvents?: number): IGunChainReference; + time?(callback: (data: DataType[K], key: ReferenceKey, time: number) => void, alsoReceiveNOldEvents?: number): IGunChainReference; /** Pushes data to a Timegraph with it's time set to Gun.state()'s time */ - time?(data: ArrayOf): void; + time?(data: DataType[K]): void; /** * Creates a new user and calls callback upon completion. diff --git a/types/index.test-d.ts b/types/index.test-d.ts index a07a6506..5dfbfd42 100644 --- a/types/index.test-d.ts +++ b/types/index.test-d.ts @@ -23,27 +23,33 @@ interface AppState { bool: boolean; specstr: 'a' | 'b'; obj: { - arr2: Array<{ foo: number; bar: string }>; + arr2: Record; }; }; - chatRoom: Array<{ by: string; message: string }>; + chatRoom: Record; } const app = new Gun(); + +// Put and get something that was previously put app.get('object') .get('bool') .put(true); app.get('object') .get('num') .put(1); -app.get('object') - .get('obj') - .get('arr2') - .set({ foo: 1, bar: '2' }); app.get('object').put({ bool: true }); +// Set and get something that was inserted using `set`. +const appSet = app.get('object') + .get('obj') + .get('arr2'); +appSet.set({ foo: 1, bar: '2' }); +// getting an auto-generated key may return an undefined value. +appSet.get('stringIdentifier').once(a => a?.foo); + expectError( app.get('object') .get('bool') diff --git a/types/types.d.ts b/types/types.d.ts index fbe24c08..37d1e440 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1,19 +1,29 @@ import { IGunChainReference } from './chain'; + export declare type ArrayOf = T extends Array ? U : never; -/** Gun does not accept Array value, so we need extract to make types correct */ -export declare type AllowArray = ArrayOf extends never ? T : ArrayOf; -export declare type DisallowArray = ArrayOf extends never ? T : never; -/** These types cannot be stored on Gun */ -export declare type AlwaysDisallowedType = T extends (...args: any[]) => void ? never : T extends { - new (...args: any[]): any; -} ? never : AccessObject; + +export declare type DisallowArray = Exclude>; + +/** These types cannot be stored on Gun (functions and classes) */ +export declare type AlwaysDisallowedType = T extends (...args: any[]) => void ? never + : T extends { new(...args: any[]): any; } ? never + : AccessObject; + export declare type AccessObject = T extends object ? { [key in keyof T]: (AlwaysDisallowedType extends never ? never : AccessObject); } : T; + /** These types cannot be stored on Gun's root level */ -export declare type DisallowPrimitives = Open extends false ? T : T extends string ? never : T extends number ? never : T extends boolean ? never : T extends null ? never : T extends undefined ? never : T; -export declare type ArrayAsRecord = ArrayOf extends never ? DataType : Record; +export declare type DisallowPrimitives = Open extends false ? T + : T extends string ? never + : T extends number ? never + : T extends boolean ? never + : T extends null ? never + : T extends undefined ? never + : T; + export declare type Saveable = Partial | string | number | boolean | null | IGunChainReference; + export declare type AckCallback = (ack: { err: Error; ok: any; @@ -21,16 +31,21 @@ export declare type AckCallback = (ack: { err: undefined; ok: string; }) => void; + export declare type IGunCryptoKeyPair = Record<'pub' | 'priv' | 'epub' | 'epriv', string>; + export interface IGunRecordNodeRawBase { '#': string; } + export interface IGunRecordNodeRawExtra extends IGunRecordNodeRawBase { '>': Record; } + export interface IGunRecordNodeRaw { '_': IGunRecordNodeRawExtra; } + export declare type IGunRecordNode = { [K in keyof DataType]: IGunRecordNodeRawBase; } & IGunRecordNodeRaw;