Skip to content
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

Add TypeScript declaration files #1578

Merged
merged 2 commits into from
May 10, 2018
Merged

Add TypeScript declaration files #1578

merged 2 commits into from
May 10, 2018

Conversation

raymondfeng
Copy link
Contributor

@raymondfeng raymondfeng commented May 3, 2018

Description

This PR adds basic TypeScript declarations for juggler related types to be referenced in LoopBack 4.

Related issues

  • connect to <link_to_referenced_issue>

Checklist

  • New tests added or existing tests modified to cover all changes
  • Code conforms with the style
    guide

@raymondfeng raymondfeng changed the title Add TypeScript declaration files [WIP] Add TypeScript declaration files May 3, 2018
Copy link
Contributor

@zbarbuto zbarbuto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - would be awesome to get typedefs out of the box. Especially for loopback core as well for things like User, Role and app.

I did notice Model is missing a few of the static methods like remoteMethod, nestRemoting and getApp.

export interface ScopedMethods<T extends ModelBase = ModelBase> {
build(data: ModelData<T>): T;

create(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the overloads for all of these methods? E.g. you can technically skip options and just provide the callback:

create(data: ModelData<T>, callback: Callback<T>): PromiseOrVoid<T>;

my preference would be to explicitly list these so that if you don't pass in a callback you know you're getting a promise:

create(data: ModelData<T>, options?: Options): Promise<T>;
create(data: ModelData<T>, callback: Callback<T>): void;
create(data: ModelData<T>, options: Options, callback: Callback<T>): void;

Also, I believe create also supports arrays of data for bulk creates:

create(data: ModelData<T> | ModelData<T>[]): Promise<T>;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zbarbuto Thank you for chiming in. It's a good idea to use overloaded method signatures. Let's do it incrementally. I would like to use the type information for LoopBack 4 soon.

For loopback module, I think there is already a community module - @types/loopback. Do you want to check out?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes have used this in the past - it does have some issues. Was only mentioning in case it was on the cards to eventually have typedefs out of the box in loopback as well.

Understood re: changing incrementally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zbarbuto I don't think I include Model in the declaration files. Please note that ModelBase is different from Model:

  • ModelBase: a base class in loopback-datasource-juggler as the common root of all models
  • Model: a class in loopback

Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great start!

I did not review the actual types in details, it's too difficult to verify their correctness manually. Can we mark TypeScript support as experimental to allow us to make backwards-incompatible fixes in semver-minor versions?

I have few high-level comments and topics to discuss, see below.

.prettierrc Outdated
@@ -0,0 +1,6 @@
{
"bracketSpacing": false,
"singleQuote": true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not mix adding Prettier with typings. Could you please open a new PR adding Prettier to our workflow (including npm test executed by CI)? Alternatively, keep these prettier-related files local only to help your IDE, don't commit them to git.

@@ -0,0 +1,18 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"compilerOptions": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused why do we need a tsconfig file, when this project does not contain any TypeScript sources to compile, only .d.ts files. Could you please clarify?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The presence of tsconfig.json file allows VsCode to validate the syntax of .d.ts files.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!

I think we should have a build step to run that validations, otherwise our .d.ts files can quickly become invalid. I consider this as a must have for this pull request.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see you have added npm run tsc, we are good here 👍

*
* Note that juggler uses Bluebird, not the native Promise.
*/
export type PromiseOrVoid<T = any> = PromiseLike<T> | void;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any import or definition of PromiseLike<T>, perhaps an oversight on your side?

I think we need to introduce some kind of a smoke test (as part of this pull request!) to at least verify that type definitions can be parsed & loaded by tsc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PromiseLike is a built-in type from lib.es5.d.ts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added npm run tsc to validate *.d.ts files.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great!

* 3. new DataSource(connectorModule, settings). For example:
* - new DataSource(connectorModule, {name: 'myDataSource})
* - new DataSource(connectorModule)
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a good idea to duplicate the jsdoc comments in typing files? I am concerned that the content in .d.ts files will quickly get out of sync with the original comments in .js files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the package is used by other modules such as @loopback/repository, VSCode uses the tsdocs from .d.ts file, IIUC.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, that makes sense.

It would be great to find a way how to automatically sync these jsdoc/tsdoc comments, but that's out of scope of this pull request.

types/model.d.ts Outdated
import {EventEmitter} from 'events';

// tslint:disable:no-any
// tslint:disable:max-line-length
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT, we don't have tslint integration in juggler, therefore we should not need any tslint overrides.

count: number;
}

export declare class PersistedModel extends ModelBase {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically speaking, there is no such thing as a PersistedModel at juggler level. We have ModelBase and DataAccessObject mixin that's added to ModelBase when a model is attached to a datasource using the default DAO implementation. Similarly, we have KeyValueAccessObject mixin that provides API for models connected to key-value stores.

The class PersistedModel is implemented in loopback, as a thin wrapper providing default DAO methods which throw a helpful message when the model was not attached to a datasource yet.

In the light of that, I feel the currently proposed typedefs are subtly incorrect and I would prefer if we could find a way how to make .d.ts files closer to the actual juggler API and behavior.

Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LB3 uses mixins at runtime to build model classes. Even though the PersistedModel is physically from loopback module, we do have the assumption of PersistedModel class in many cases in loopback-datasource-juggler.

It's hard to describe such contracts in other forms such as interfaces to allow both static and prototype methods/properties.

@raymondfeng raymondfeng force-pushed the ts-definitions branch 3 times, most recently from a11a3fb to ab3412d Compare May 8, 2018 21:39
@bajtos
Copy link
Member

bajtos commented May 9, 2018

LB3 uses mixins at runtime to build model classes. Even though the PersistedModel is physically from loopback module, we do have the assumption of PersistedModel class in many cases in loopback-datasource-juggler.

It's hard to describe such contracts in other forms such as interfaces to allow both static and prototype methods/properties.

I'll see. This is an interesting problem, I may give it a try myself. For now, I am ok with a suboptimal solution that works right now.

@@ -13,5 +13,5 @@ npm-debug.log
.project
test/memory.json
.nyc_output

dist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add dist to .npmignore too.

@@ -0,0 +1,18 @@
{
"$schema": "http://json.schemastore.org/tsconfig",
"compilerOptions": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see you have added npm run tsc, we are good here 👍

@bajtos
Copy link
Member

bajtos commented May 9, 2018

Few more comments (see above), I think this is almost ready to be landed. My expectation is that we will be fixing any bugs as we discover them from real-world usage, thus this initial typings can be landed quickly.

I feel it's really important to clearly set the expectations about the stability of the TypeScript type definitions. Could you please add a bold comment to index.d.ts to mark TypeScript support as experimental and explicitly tell the users that backwards-incompatible fixes may come in semver-minor versions?

Copy link
Contributor

@b-admike b-admike left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff @raymondfeng. I just looked at datasource.d.ts and was wondering why we have some missing methods compared to https://apidocs.strongloop.com/loopback-datasource-juggler/#datasource? Perhaps it's because we'd like to add them incrementally?

connected?: boolean;
connecting?: boolean;

connector?: any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

@raymondfeng raymondfeng force-pushed the ts-definitions branch 2 times, most recently from d0f08c4 to ebcf6de Compare May 9, 2018 18:14
@raymondfeng
Copy link
Contributor Author

@bajtos @zbarbuto @b-admike Any more comments before I merge the PR?

Copy link
Contributor

@b-admike b-admike left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 , although I haven't looked through all the details. I'm good with the plan to modify incrementally.

@zbarbuto
Copy link
Contributor

zbarbuto commented May 9, 2018

Agree with @b-admike - LGTM for a first-pass

Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@raymondfeng raymondfeng changed the title [WIP] Add TypeScript declaration files Add TypeScript declaration files May 10, 2018
@raymondfeng raymondfeng merged commit c955802 into master May 10, 2018
@raymondfeng raymondfeng deleted the ts-definitions branch May 10, 2018 13:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants