Address concerns around count typings (#3249)

* Use number instead of number | string for return type of count

Closes #3247

* Use an alias instead of interface for DeferredKeySelection

This prevents typescript from complaining when it has to be used in an exported signature without us having to expose internal type as public

Closes #3259

* Make count result type overridable

* Disable interface-over-type-literal rule
This commit is contained in:
Lorefnon 2019-06-06 11:54:28 +05:30 committed by Igor Savin
parent c431ffc35a
commit 501d58a6d9
3 changed files with 42 additions and 11 deletions

23
types/index.d.ts vendored
View File

@ -11,6 +11,7 @@
import events = require('events'); import events = require('events');
import stream = require('stream'); import stream = require('stream');
import Bluebird = require('bluebird'); import Bluebird = require('bluebird');
import ResultTypes = require('./result');
// # Generic type-level utilities // # Generic type-level utilities
@ -86,7 +87,7 @@ type MappedAliasType<TBase, TAliasMapping> = {} & {
// but the keys being selected or additional properties being augmented are not // but the keys being selected or additional properties being augmented are not
// all known at once and we would want to effectively build up a partial/intersection // all known at once and we would want to effectively build up a partial/intersection
// over multiple steps. // over multiple steps.
interface DeferredKeySelection< type DeferredKeySelection<
// The base of selection. In intermediate stages this may be unknown. // The base of selection. In intermediate stages this may be unknown.
// If it remains unknown at the point of resolution, the selection will fall back to any // If it remains unknown at the point of resolution, the selection will fall back to any
TBase, TBase,
@ -106,7 +107,7 @@ interface DeferredKeySelection<
TIntersectProps extends {} = {}, TIntersectProps extends {} = {},
// Extra props which will be unioned with the result // Extra props which will be unioned with the result
TUnionProps = never TUnionProps = never
> { > = {
// These properties are not actually used, but exist simply because // These properties are not actually used, but exist simply because
// typescript doesn't end up happy when type parameters are unused // typescript doesn't end up happy when type parameters are unused
_base: TBase; _base: TBase;
@ -116,7 +117,7 @@ interface DeferredKeySelection<
_single: TSingle; _single: TSingle;
_intersectProps: TIntersectProps; _intersectProps: TIntersectProps;
_unionProps: TUnionProps; _unionProps: TUnionProps;
} };
// An companion namespace for DeferredKeySelection which provides type operators // An companion namespace for DeferredKeySelection which provides type operators
// to build up participants of intersection/partial over multiple invocations // to build up participants of intersection/partial over multiple invocations
@ -273,8 +274,7 @@ type AggregationQueryResult<TResult, TIntersectProps2> = ArrayIfAlready<
// deferring an index access operation (TBase[TKey]) over a potentially // deferring an index access operation (TBase[TKey]) over a potentially
// unknown initial type of TBase and potentially never initial type of TKey // unknown initial type of TBase and potentially never initial type of TKey
interface DeferredIndex<TBase, TKey extends string> type DeferredIndex<TBase, TKey extends string> = DeferredKeySelection<TBase, TKey, false, {}, true>;
extends DeferredKeySelection<TBase, TKey, false, {}, true> {}
declare namespace DeferredIndex { declare namespace DeferredIndex {
type Augment< type Augment<
@ -297,9 +297,7 @@ type ResolveResult<S> = DeferredKeySelection.Resolve<S>;
type Callback = Function; type Callback = Function;
type Client = Function; type Client = Function;
interface Dict<T = any> { type Dict<T = any> = { [k: string]: T; };
[k: string]: T;
}
type SafePick<T, K extends keyof T> = T extends {} ? Pick<T, K> : any; type SafePick<T, K extends keyof T> = T extends {} ? Pick<T, K> : any;
@ -382,6 +380,11 @@ declare namespace Knex {
type TableDescriptor = string | Knex.Raw | Knex.QueryBuilder; type TableDescriptor = string | Knex.Raw | Knex.QueryBuilder;
type Lookup<TRegistry extends {}, TKey extends string, TDefault = never> =
TKey extends keyof TRegistry ?
TRegistry[TKey] :
TDefault;
// //
// QueryInterface // QueryInterface
// //
@ -498,8 +501,8 @@ declare namespace Knex {
limit(limit: number): QueryBuilder<TRecord, TResult>; limit(limit: number): QueryBuilder<TRecord, TResult>;
// Aggregation // Aggregation
count: AssymetricAggregation<TRecord, TResult, number | string>; count: AssymetricAggregation<TRecord, TResult, Lookup<ResultTypes.Registry, "Count", number | string>>;
countDistinct: AssymetricAggregation<TRecord, TResult, number | string>; countDistinct: AssymetricAggregation<TRecord, TResult, Lookup<ResultTypes.Registry, "Count", number | string>>;
min: TypePreservingAggregation<TRecord, TResult>; min: TypePreservingAggregation<TRecord, TResult>;
max: TypePreservingAggregation<TRecord, TResult>; max: TypePreservingAggregation<TRecord, TResult>;
sum: TypePreservingAggregation<TRecord, TResult>; sum: TypePreservingAggregation<TRecord, TResult>;

27
types/result.d.ts vendored Normal file
View File

@ -0,0 +1,27 @@
// This empty interface serves as a placeholder which userland code can augment to
// override result types.
//
// Currently only available result type which is overridable is Count, which defaults to
// number | string;
//
// Following example in userland code will alter this to be just number:
//
// declare module "knex/types/result" {
// interface Registry {
// Count: number;
// }
// }
//
// Prior discussion: https://github.com/tgriesser/knex/issues/3247
export interface Registry {
// We can't actually have default types here
// because typescript's augmentation will not permit
// overriding the type of a property already present.
//
// But the effective defaults are documented below:
//
// Count: number | string;
//
// Refer to Knex.Lookup type operator to see how the defaults
// are actually specified.
}

View File

@ -9,6 +9,7 @@
"unified-signatures": false, "unified-signatures": false,
"no-unnecessary-qualifier": false, "no-unnecessary-qualifier": false,
"strict-export-declare-modifiers": false, "strict-export-declare-modifiers": false,
"only-arrow-functions": false "only-arrow-functions": false,
"interface-over-type-literal": false
} }
} }