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
Fix type definitions for PersistedModel API #1599
Conversation
Callback's first argument is an optional Error now. Was: required `any`. PersistedModel methods return `PersistedModel` now. Before this change, methods were returning `PersistedData` (`PersistedModel | AnyObject`). The problem with `AnyObject` is that it does not contain any `PersistedModel` instance data and cannot be assigned to functions expecting `Partial<PersistedModel>`. As a result, consumers of this API were forced to either cast the result to `PersistedModel` (which feels wrong) or deal with the `AnyObject` case (which never happen at runtime). Fix definition of `ModelData<T>` to `T | Partial<T>`. Before this change, `ModelData` allowed any values not related to the actual model at all, for example arrays.
types/common.d.ts
Outdated
@@ -18,7 +18,7 @@ export type Options = AnyObject<any>; | |||
/** | |||
* Type alias for Node.js callback functions | |||
*/ | |||
export type Callback<T = any> = (err: any, result?: T) => void; | |||
export type Callback<T = any> = (err?: Error | null, result?: T) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Enable the following usage patterns:
callback()
callback(null)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't it be err?: any
- AFAIK normally any value passed to first parameter that's not null / undefined means an error. So ... for example, I can pass a string into the Callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Node.js does allow the error parameter to be any
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough, I'll change it to err?: any
.
types/model.d.ts
Outdated
@@ -246,4 +246,4 @@ export declare class ModelBuilder extends EventEmitter { | |||
* Union export type for model instance or plain object representing the model | |||
* instance | |||
*/ | |||
export type ModelData<T extends ModelBase = ModelBase> = T | AnyObject; | |||
export type ModelData<T extends ModelBase = ModelBase> = T | Partial<T>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strangely enough, AnyObject
allows arbitrary values not related to ModelBase at all, for example an array. This is a problem in PersistedModel API, where the data
argument of methods like create
or upsert
suddenly allows callers to provide an array, despite the fact that these methods don't support batch mode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably should introduce a DeepPartial
as follows. It's used in TypeORM too.
export type DeepPartial<T> = { [P in keyof T]?: DeepPartial<T[P]>; };
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't T | Partial<T>
be the same as Partial<T>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably should introduce a DeepPartial as follows. It's used in TypeORM too.
Will do.
wouldn't T | Partial be the same as Partial?
From compiler's point of view, I think it's the same, because T
can be assigned to Partial<T>
. From documentation perspective, I feel T | Partial<T>
is communicating the intent better.
): PromiseOrVoid<PersistedModel>; | ||
|
||
static create( | ||
data: PersistedData[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an overload for batch create mode, where an array of data objects is accepted and the method returns an array of model instances created.
@raymondfeng @virkt25 @jannyHou Thank you for the feedback, I have addressed your comments in 6f3675b. LGTY now? |
Callback's first argument is an optional Error now. Was: required
any
.PersistedModel methods return
PersistedModel
now. Before this change, methods were returningPersistedData
(PersistedModel | AnyObject
). The problem withAnyObject
is that it does not contain anyPersistedModel
instance data and cannot be assigned to functions expectingPartial<PersistedModel>
. As a result, consumers of this API were forced to either cast the result toPersistedModel
(which feels wrong) or deal with theAnyObject
case (which never happen at runtime).Fix definition of
ModelData<T>
toT | Partial<T>
. Before this change,ModelData
allowed any values not related to the actual model at all, for example arrays.These problems were discovered while working on loopbackio/loopback-next#1475. The fixes presented in this pull request seem to be backwards compatible, at least as far as loopback-next tests are concerned.