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

Improve internal types #19517

Merged
merged 4 commits into from
May 24, 2021
Merged

Improve internal types #19517

merged 4 commits into from
May 24, 2021

Conversation

wagenet
Copy link
Member

@wagenet wagenet commented Apr 28, 2021

Improve types for @ember/object

Includes:

  • Object, { action } from '@ember/object'
  • CoreObject from '@ember/object/core'
  • Observable from '@ember/object/observable'
  • { dependentKeyCompat } from '@ember/object/compat'

Note that types for extend, reopen, and reopenClass are not
exported. Also, get and set have naive types. All of these will
be deprecated in future releases.

Many types were copied from DT. We should make sure to give appropriate credit, but I suspect we may already be doing that.

@@ -2752,16 +2803,7 @@ if (ROUTER_EVENTS) {
},
};

Route.reopen(ROUTER_EVENT_DEPRECATIONS, {
_paramsFor(routeName: string, params: {}) {
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm pretty sure it was a bug for this to be in a conditional reopen. We always depend on _paramsFor.

Copy link
Contributor

@chriskrycho chriskrycho left a comment

Choose a reason for hiding this comment

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

Thanks for tackling this! One note: if possible I think it'd be extremely helpful to separate the functional changes from the type-only changes. In particular, I'm extremely leery of any shuffling in the router here (once bitten twice shy, and the router has bitten about four months off of my life 😂).

@@ -147,7 +148,8 @@
"simple-dom": "^1.4.0",
"testem": "^3.1.0",
"testem-failure-only-reporter": "^0.0.1",
"tslint": "^5.20.1"
"tslint": "^5.20.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

Definitely for a later PR: we should prioritize getting off of TSLint and swap in a compatible ESLint config via @typescript-eslint/parser and friends.

mergeProps(meta, currentMixin, descs, values, base, keys, keysWithSuper);
mergeProps(
meta,
currentMixin as { [key: string]: any },
Copy link
Contributor

Choose a reason for hiding this comment

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

?: could we do Record<string, unknown> here instead? Record is generally a bit nicer than { [key: string]: T } and unknown is definitely a win over any, but if that entails more sweeping changes, we can follow on later.

Comment on lines 70 to 77
concreteImplementation?: EmberLocation;

implementation = 'auto';

// FIXME: This is never set
// See https://github.com/emberjs/ember.js/issues/19515
documentMode: number | undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: These look to be internal (they're not details currently available in the public API), so in the interest of clarity and making it easy to process with API tooling later, can we mark them as @private (or possibly @internal)?

Suggested change
concreteImplementation?: EmberLocation;
implementation = 'auto';
// FIXME: This is never set
// See https://github.com/emberjs/ember.js/issues/19515
documentMode: number | undefined;
/** @private */
concreteImplementation?: EmberLocation;
/** @private */
implementation = 'auto';
// FIXME: This is never set
// See https://github.com/emberjs/ember.js/issues/19515
/** @private */
documentMode: number | undefined;

@default '/'
*/
// Added in reopen to allow overriding via extend
rootURL!: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

For all of these newly-introduced definitions on the class, can we use declare instead of !? As an alternative, we could do that in a follow-on which does them across the whole class so that the class is marked consistently (which I'm guessing is why you didn't do it in this pass). Feel free to drop this and the related suggestions throughout if you just want to punt it for that reason.

For now, the compiler will emit the same JS given the current tsconfig.json, but that'll future-proof nicely for switching the useDefineForClassFields flag.

Suggested change
rootURL!: string;
declare rootURL: string;

(I'm not adding suggestions below for this in this class because I suspect you're just going for consistency. I am adding suggestions in classes where it would be consistent, or where you could make it consistent trivially, i.e. where there aren't a bunch of other ! declarations already.)

Comment on lines 62 to 63
location!: any;
baseURL!: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
location!: any;
baseURL!: string;
declare location: any;
declare baseURL: string;

if (descriptorForProperty(controller, prop) === undefined) {
let desc = lookupDescriptor(controller, prop);
// Set in reopen
actions!: Record<string, Function>;
Copy link
Contributor

Choose a reason for hiding this comment

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

Better here to provide an "any function"-style signature, either by creating a standard alias to use for that or by doing it inline here:

Suggested change
actions!: Record<string, Function>;
actions!: Record<string, (...args: any[]) => any>;

or

Suggested change
actions!: Record<string, Function>;
actions!: Record<string, AnyFunction>;

where

type AnyFunction = (...args: any[]) => any;

This has the same level of safety around those function parameters as Function (namely: none, but that's fine for these purposes!) but it prevents assigning class constructors here, so it's a small but real improvement. It also allows things to use extends with it correctly for inferring arguments etc.

templateName = 'posts/list'
});
```
let current: any;
Copy link
Contributor

Choose a reason for hiding this comment

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

When we make this change (whether in this PR or another), I think we should be able to do:

Suggested change
let current: any;
let current: Route | undefined;

Comment on lines 2396 to 2401
interface PartialRenderOptions {
into?: string;
outlet?: string;
controller?: string | any;
model?: {};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd suggest using the utility types TS ships here to keep this in sync with RenderOptions:

Suggested change
interface PartialRenderOptions {
into?: string;
outlet?: string;
controller?: string | any;
model?: {};
}
type PartialRenderOptions = Partial<
Pick<RenderOptions, 'into' | 'outlet' | 'controller' | 'model'>
>;

On a related note: model here is {} but is unknown in RenderOptions – is that intentional? 😬

Comment on lines +3 to +5
/**
* This mixin provides properties and property observing functionality, core features of the Ember object model.
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

A discussion point (cc. @pzuraq @dfreeman @jamescdavis): throughout, this uses the keyof this to make keys support both auto-complete and type-checking against property keys. However, it drops the feature from DT where it returns the type. I think, if we drop support for building types mixins, we can actually enable strictFunctionTypes and keep the return type correct?

import { dependentKeyCompat } from '@ember/object/compat';
import { expectTypeOf } from 'expect-type';

expectTypeOf(dependentKeyCompat).toMatchTypeOf<Function>();
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
expectTypeOf(dependentKeyCompat).toMatchTypeOf<Function>();
expectTypeOf(dependentKeyCompat).toMatchTypeOf<PropertyDecorator>();

Copy link
Contributor

@chriskrycho chriskrycho left a comment

Choose a reason for hiding this comment

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

Thanks for these!

@wagenet wagenet marked this pull request as ready for review May 24, 2021 18:20
.eslintrc.js Outdated Show resolved Hide resolved
Comment on lines 3 to 15
// export {
// aliasMethod,
// computed,
// defineProperty,
// get,
// getProperties,
// getWithDefault,
// notifyPropertyChange,
// observer,
// set,
// setProperties,
// trySet,
// } from '@ember/-internals/metal';
Copy link
Member

Choose a reason for hiding this comment

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

Why is this here? In general, I think we'd prefer to avoid landing a commented out section like this (basically we should bring it back, delete it, or add a comment explaining why its commented).

Copy link
Member Author

Choose a reason for hiding this comment

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

It's stuff that we want to export but isn't ready yet. I'll remove it and add it back properly in another PR.

Includes:
  - Object, { action } from '@ember/object'
  - CoreObject from '@ember/object/core'
  - Observable from '@ember/object/observable'

Note that types for `extend`, `reopen`, and `reopenClass` are not
exported. Also, `get` and `set` have naive types. All of these will
be deprecated in future releases.
@stefanpenner
Copy link
Member

stefanpenner commented Jun 3, 2021

@wagenet these files appear to unexpectedly end up in the build output, which seems unintentional.


potential fix posted: #19589

@stefanpenner
Copy link
Member

stefanpenner commented Jun 3, 2021

^^ fix landed, all should be unblocked.

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