Future public @ember/engine types#19923
Conversation
ea75656 to
dd914f6
Compare
e34ab4a to
cd198dd
Compare
chriskrycho
left a comment
There was a problem hiding this comment.
Will finish this review tomorrow, but WIP feedback!
| @return {any} | ||
| */ | ||
| lookup(fullName: string, options: LookupOptions): any { | ||
| lookup<T>(fullName: string, options?: TypeOptions): T | undefined { |
There was a problem hiding this comment.
This should actually return unknown, since it's impossible to infer from the arguments what the return type T would actually be.
| lookup<T>(fullName: string, options?: TypeOptions): T | undefined { | |
| lookup(fullName: string, options?: TypeOptions): unknown { |
I know this matches the other implementations, but we should take care to move toward rather than away from safety with this work where our hands are not already tied in some way.
I expect you introduced this because there is client code which is relying on being able to freely cast because of the previous any return type?
There was a problem hiding this comment.
This makes sense. I’ll give it a second look tomorrow.
| readonly registrations: { [key: string]: object | undefined }; | ||
| _localLookupCache: { [key: string]: object | undefined }; | ||
| readonly _normalizeCache: { [key: string]: string | undefined }; | ||
| readonly _options: { [key: string]: TypeOptions | undefined }; | ||
| readonly _resolveCache: { [key: string]: object | undefined }; | ||
| readonly _typeOptions: { [key: string]: TypeOptions | undefined }; |
There was a problem hiding this comment.
- Can we just use
Record<string, TypeOptions>etc. here? - It looks like this as well as the
incheck below are both because we don't yet havenoUncheckedIndexAccessenabled, so we're sort of pushing that safety in manually?
There was a problem hiding this comment.
We do have noUncheckedIndexAccess now. I’ll revisit this.
| getOptions(fullName: string): TypeOptions | undefined { | ||
| let normalizedName = this.normalize(fullName); | ||
| let options = this._options[normalizedName]; | ||
| let options = normalizedName in this._options ? this._options[normalizedName] : undefined; |
There was a problem hiding this comment.
Hmm. This shouldn't be complaining about the access. 🤔 (See playground.) Since it's a string index, and given the type you wrote, it should correctly resolve it in either the Record or the index type form. What error was TS giving you here?
There was a problem hiding this comment.
Not sure what was happening before but it seems ok now.
| owner: Owner, | ||
| options?: LookupOptions | ||
| ): Option<Factory<{}, {}>> { | ||
| function componentFor(name: string, owner: Owner): Option<Factory<{}, {}>> { |
There was a problem hiding this comment.
This looks like an unrelated-to-types change – is this a dead code path or something?
There was a problem hiding this comment.
The type was incorrect. factoryFor doesn't take options.
There was a problem hiding this comment.
Glad we caught it by doing this, then. Thanks! 😃
| factoryFor<T, C>(fullName: string, options?: LookupOptions): Factory<T, C> | undefined; | ||
| register<T, C>(fullName: string, factory: Factory<T, C>, options?: LookupOptions): void; | ||
| hasRegistration(name: string, options?: LookupOptions): boolean; | ||
| lookup<T>(fullName: string, options?: TypeOptions): T | undefined; |
There was a problem hiding this comment.
As before, I'm fine if we leave this for now, but we should start working to eliminate it. 😩
| } | ||
| declare const ContainerProxy: Mixin; | ||
|
|
||
| export { ContainerProxy as default }; |
There was a problem hiding this comment.
I believe the normal export default form should work; does it not for some reason?
| export { ContainerProxy as default }; | |
| export default ContainerProxy; |
| } | ||
| declare const RegistryProxyMixin: Mixin; | ||
|
|
||
| export { RegistryProxyMixin as default }; |
There was a problem hiding this comment.
| export { RegistryProxyMixin as default }; | |
| export default RegistryProxyMixin; |
cd198dd to
47ff27b
Compare
47ff27b to
b97e01a
Compare
chriskrycho
left a comment
There was a problem hiding this comment.
Guide:
| Mark | Meaning |
|---|---|
| ? | informational, non-blocking |
| ~ | not great, non-blocking |
| X | blocking |
Spoilers: no X, so
.
| if (layout === undefined) { | ||
| if (layoutName !== undefined) { | ||
| let _factory = owner.lookup<TemplateFactory>(`template:${layoutName}`); | ||
| let _factory = owner.lookup(`template:${layoutName}`) as TemplateFactory; |
There was a problem hiding this comment.
?: Is this cast safe? If so, why? (I see that it was already here.)
There was a problem hiding this comment.
I don't know that it's safe, but it's how it was before so it probably is. I figure having as is safer (as in we know we're doing something potentially risky) than the way it was before where it wasn't clear that there was risk!
| if ((owner.lookup('-environment:main') as Environment)!.isInteractive) { | ||
| this.__dispatcher = owner.lookup('event_dispatcher:main') as EventDispatcher; |
There was a problem hiding this comment.
~: Would be good to follow on with dev-time assertions instead of casting.
|
|
||
| ensureEventSetup(actionState: ActionState): void { | ||
| let dispatcher = actionState.owner.lookup<EventDispatcher>('event_dispatcher:main'); | ||
| let dispatcher = actionState.owner.lookup('event_dispatcher:main') as EventDispatcher; |
There was a problem hiding this comment.
?/~: as above re: casting and safety
| let templateFullName = `template:components/${name}`; | ||
|
|
||
| return owner.lookup(templateFullName, options) || null; | ||
| return (owner.lookup(templateFullName, options) as Template) || null; |
There was a problem hiding this comment.
~: Could use a safety comment here in the future.
There was a problem hiding this comment.
Yeah, again I don't know that this is actually safe!
| const factory = owner.factoryFor(`helper:${name}`) as | ||
| | Factory<SimpleHelper, HelperFactory<SimpleHelper>> | ||
| | Factory<HelperInstance, HelperFactory<HelperInstance>>; |
There was a problem hiding this comment.
?/~: as above on the cast.
There was a problem hiding this comment.
Yup, unsure this is safe, but it seems like it must be.
| this.namespace = owner.lookup('application:main'); | ||
|
|
||
| let bucketCache: BucketCache | undefined = owner.lookup(P`-bucket-cache:main`); | ||
| let bucketCache = owner.lookup(P`-bucket-cache:main`) as BucketCache | undefined; |
| */ | ||
| export function getRootViews(owner: Owner): View[] { | ||
| let registry = owner.lookup<Dict<View>>('-view-registry:main')!; | ||
| let registry = owner.lookup('-view-registry:main') as Dict<View>; |
There was a problem hiding this comment.
~: as throughout, for reference.
| ).toEqualTypeOf<void>(); | ||
|
|
||
| expectTypeOf(instance.lookup<Store>('service:store')).toEqualTypeOf<Store | undefined>(); | ||
| expectTypeOf(instance.lookup('service:store')).toEqualTypeOf<unknown>(); |
There was a problem hiding this comment.
If we add that registry, these will (happily!) flag it up for us as a case where it no longer equals that type. 🎉
| */ | ||
| export default function captureRenderTree(app: Owner): CapturedRenderNode[] { | ||
| let renderer = expect(app.lookup<Renderer>('renderer:-dom'), `BUG: owner is missing renderer`); | ||
| let renderer = expect(app.lookup('renderer:-dom') as Renderer, `BUG: owner is missing renderer`); |
There was a problem hiding this comment.
~: could use a better assertion to check that it's not just present but is the right/expected thing.
| @private | ||
| */ | ||
| export function getEngineParent(engine) { | ||
| export function getEngineParent(engine: EngineInstance): EngineInstance | undefined { |
No description provided.