-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Improve internal types #19517
Conversation
@@ -2752,16 +2803,7 @@ if (ROUTER_EVENTS) { | |||
}, | |||
}; | |||
|
|||
Route.reopen(ROUTER_EVENT_DEPRECATIONS, { | |||
_paramsFor(routeName: string, params: {}) { |
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.
I'm pretty sure it was a bug for this to be in a conditional reopen. We always depend on _paramsFor
.
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.
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", |
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.
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 }, |
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.
?: 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.
concreteImplementation?: EmberLocation; | ||
|
||
implementation = 'auto'; | ||
|
||
// FIXME: This is never set | ||
// See https://github.com/emberjs/ember.js/issues/19515 | ||
documentMode: number | undefined; |
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.
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
)?
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; |
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.
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.
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.)
location!: any; | ||
baseURL!: string; |
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.
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>; |
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.
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:
actions!: Record<string, Function>; | |
actions!: Record<string, (...args: any[]) => any>; |
or
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; |
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.
When we make this change (whether in this PR or another), I think we should be able to do:
let current: any; | |
let current: Route | undefined; |
interface PartialRenderOptions { | ||
into?: string; | ||
outlet?: string; | ||
controller?: string | any; | ||
model?: {}; | ||
} |
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.
I'd suggest using the utility types TS ships here to keep this in sync with RenderOptions
:
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? 😬
/** | ||
* This mixin provides properties and property observing functionality, core features of the Ember object model. | ||
*/ |
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.
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>(); |
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.
expectTypeOf(dependentKeyCompat).toMatchTypeOf<Function>(); | |
expectTypeOf(dependentKeyCompat).toMatchTypeOf<PropertyDecorator>(); |
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.
Thanks for these!
packages/@ember/object/index.d.ts
Outdated
// export { | ||
// aliasMethod, | ||
// computed, | ||
// defineProperty, | ||
// get, | ||
// getProperties, | ||
// getWithDefault, | ||
// notifyPropertyChange, | ||
// observer, | ||
// set, | ||
// setProperties, | ||
// trySet, | ||
// } from '@ember/-internals/metal'; |
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.
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).
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.
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.
^^ fix landed, all should be unblocked. |
Improve types for @ember/object
Includes:
Note that types for
extend
,reopen
, andreopenClass
are notexported. Also,
get
andset
have naive types. All of these willbe 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.