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

Use Typescript #425

Merged
merged 1 commit into from Feb 26, 2019
Merged

Use Typescript #425

merged 1 commit into from Feb 26, 2019

Conversation

BBosman
Copy link
Contributor

@BBosman BBosman commented Feb 7, 2019

Pull Request

πŸ“– Description

Reap the benefits of the recent Typescript 3.3 update.

🎫 Issues

n/a

πŸ‘©β€πŸ’» Reviewer Notes

Notable changes:

  • Removed the T & any hack from Constructable, as it's no longer needed.
  • That triggered some typing errors that where previously masked due the use of any, so I fixed those.
  • Removed some linting supressions that are no longer needed, as the false positives no longer trigger.
  • Minor linting changes

πŸ“‘ Test Plan

CircleCI

⏭ Next Steps

n/a

@BBosman BBosman requested a review from fkleuver February 7, 2019 22:57
@codeclimate
Copy link

codeclimate bot commented Feb 7, 2019

Code Climate has analyzed commit c3b6d46 and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 100.0% (50% is the threshold).

This pull request will bring the total coverage in the repository to 90.6% (0.0% change).

View more on Code Climate.

@BBosman
Copy link
Contributor Author

BBosman commented Feb 7, 2019

No clue why unit_test_node is failing though.

@fkleuver
Copy link
Member

fkleuver commented Feb 8, 2019

@BBosman There's probably a whole chunk of tests failing actually, I'm seeing this TS compiler error in the node tests:

SyntaxError: The requested module 'file:///home/circleci/repo/packages/runtime/dist/build/templating/lifecycle-render.js' does not provide an export named '$hydrateElement'

The browser tests will simply fail to load entirely if there is some error like a module import that cant be resolved which results in those tests not running (that's where the -1.5% coverage comes from). It's probably a good idea to turn on the type checker in webpack. Anyway, the node tests do go through normal typescript compilation so they will actually tell you what's wrong during compilation of the tests. Webpack completely suppresses test compiler errors with the current settings (this was done for speed)

@BBosman
Copy link
Contributor Author

BBosman commented Feb 8, 2019

@fkleuver I did see that error, but I don't understand why it's giving it.

The file src/templating/lifecycle-render.ts has this:

export function $hydrateElement(this: Writable<ICustomElement>, flags: LifecycleFlags, parentContext: IServiceLocator, host: INode, options: IElementHydrationOptions = PLATFORM.emptyObject): void {
  // ...
}

And dist/build/templating/lifecycle-render.js has this:

export function $hydrateElement(flags, parentContext, host, options = PLATFORM.emptyObject) {
  // ...
}

So it is there and being exported imho.

It is missing from dist/templating/lifecycle-render.d.ts though.

@fkleuver
Copy link
Member

fkleuver commented Feb 8, 2019

@BBosman It's marked internal so it doesn't end up in the type defs, that's why it's imported via a relative import

@BBosman
Copy link
Contributor Author

BBosman commented Feb 8, 2019

@fkleuver That explains why it's missing in the d.ts file, but not why unit_test_node fails as I can see the function it says is not being exported in the file where it says it's not being exported from.

(I tried removing the internal, but that didn't solve it. I also tried renaming it, thinking it maybe didn't like the $-prefix, but that also doesn't solve it.)

@fkleuver
Copy link
Member

fkleuver commented Feb 9, 2019

@BBosman there is a compiler error in packages/runtime/test/resources/custom-element.resource.spec.ts but that's not the thing causing this though. Just wanted to mention it. I'm trying to narrow down why it's complaining about $hydrateElement

@fkleuver
Copy link
Member

fkleuver commented Feb 9, 2019

@BBosman Looks like this was a regression in esm@3.2.1 which was fixed again in esm@3.2.4: somewhat related to this (you currently have it on esm@3.2.3. That's the loader mocha uses.
Upgrading to esm@3.2.4 should get rid of that strange $hydrateElement error. It does however expose the other compiler error I pointed out in my previous comment.

Now, suppressing that with as any like so: expect(CustomElementResource.isType(type as any)).to.equal(false); gets the node tests to fully run again. The problem with that, is that CustomElementResource.isType is very public API and shouldn't be causing type errors when passing in a constructor with the wrong prototype.

We might actually want to keep Constructable around for this purpose. The semantic difference between Constructable and Class is that Constructable is, well, not necessarily a class and does not have a strongly typed prototype, which is necessary in certain cases.

packages/kernel/src/di.ts Outdated Show resolved Hide resolved
@@ -21,7 +21,7 @@ const slice = Array.prototype.slice;

export function createElement<T extends INode = Node>(
dom: IDOM<T>,
tagOrType: string | Constructable,
tagOrType: string | Class,
Copy link
Member

Choose a reason for hiding this comment

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

Will this still work if you pass a regular function to it (I'm not even sure if that worked before, but I just got to think of it)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, it will give a type error. Changing it would have to be downstream as well, cause createElementForType has it as well.

@codecov
Copy link

codecov bot commented Feb 9, 2019

Codecov Report

Merging #425 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #425      +/-   ##
==========================================
+ Coverage   90.31%   90.31%   +<.01%     
==========================================
  Files         139      139              
  Lines       11282    11286       +4     
  Branches      790      790              
==========================================
+ Hits        10189    10193       +4     
  Misses       1093     1093
Impacted Files Coverage Ξ”
packages/runtime-html/src/projectors.ts 94.87% <ΓΈ> (ΓΈ) ⬆️
packages/runtime/src/binding/connectable.ts 100% <ΓΈ> (ΓΈ) ⬆️
packages/runtime-html/src/dom.ts 94.63% <ΓΈ> (ΓΈ) ⬆️
packages/runtime/src/templating/lifecycle-bind.ts 92.1% <ΓΈ> (ΓΈ) ⬆️
packages/runtime/src/resources/value-converter.ts 85% <100%> (ΓΈ) ⬆️
packages/runtime/src/resources/binding-behavior.ts 85.71% <100%> (+0.71%) ⬆️
packages/kernel/src/di.ts 89.15% <100%> (ΓΈ) ⬆️
packages/router/src/nav-route.ts 80.95% <100%> (ΓΈ) ⬆️
packages/runtime/src/templating/bindable.ts 90% <100%> (ΓΈ) ⬆️
packages/jit/src/binding-command.ts 96% <100%> (+0.05%) ⬆️
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Ξ” = absolute <relative> (impact), ΓΈ = not affected, ? = missing data
Powered by Codecov. Last update 463bcbc...c3b6d46. Read the comment docs.

@BBosman
Copy link
Contributor Author

BBosman commented Feb 9, 2019

@fkleuver The esm update indeed fixed the export issue.

I also reverted the Constructable -> Class change, as it had too many unintended side-effects.

The problem with that, is that CustomElementResource.isType is very public API and shouldn't be causing type errors when passing in a constructor with the wrong prototype.

Isn't the purpose of an isType type guard to cause type errors when passing in something invalid?

@fkleuver
Copy link
Member

fkleuver commented Feb 10, 2019

@BBosman Well, technically you can't pass in anything that's "invalid". There are no type constraints on what can be a custom element or custom attribute apart from it being constructable. What that method gives you is the ability to tell whether something is a certain resource type, and if it is, inside the if that resource will be strongly typed (as per the interface of that resource, merged with the class type you passed in).
It's not necessarily supposed to give type errors when calling it. For example, you might pass in a custom attribute or something that is not a resource at all. It will simply return false so at runtime you're guarded against making the wrong assumptions.

Put simply, truly type checking the resources is too hard while TypeScript doesn't support stuff like decorator type merging and properly deriving prototypes, etc. It will go wrong too often and cause annoyances. I tried really really hard and spent several solid evenings on it. What's left is just a mess of stuff that didn't really turn out to work but I haven't had the time to clean up yet.

@fkleuver
Copy link
Member

@BBosman sorry for not following up for a bit, is there something you still needed help with on this PR?

@BBosman
Copy link
Contributor Author

BBosman commented Feb 14, 2019

@fkleuver No problem. Life got in the way here, so haven't had time to look at it from my side either.

I just rebased on master and pushed the most recent version (and updated the PR description).

The only open issue is the failing unit_test_node due to the isType issue mentioned above. It's also the root cause of not being able to make the other casting changes requested above.

The problem is that I don't know how to fix it, even with your (extended) explanation, so some hands on help would be appreciated.

@BBosman
Copy link
Contributor Author

BBosman commented Feb 14, 2019

Minor update: Had to pin chromedriver to ~2.45.0, as 2.46.0 requires a newer version of Chrome than the one that's running on CircleCI.

@fkleuver
Copy link
Member

For starters let's separate dependency updates from refactors, because dependency updates generally don't need much review and could have been merged a long time ago. If the refactor depends on it and you don't want to have to wait for review/merge, it's fine if you create a new branch off the previous one and have a second PR with everything included. Then, once the first is merged, you can merge again and the diff will be normalized to only the latest changes automatically

Do you think you can split it up so we can eliminate the deps from being a factor?

@BBosman BBosman changed the title Upgrade Typescript Use Typescript Feb 16, 2019
@BBosman
Copy link
Contributor Author

BBosman commented Feb 16, 2019

@fkleuver Split of the dependency updates and the InjectArray changes, so it's now down to the removal of the Constructable/any hack (and removing some no longer needed tslint:disable comments).

Unfortunately the problem still remains. I can fix it by using unknown, but I don't know if that's the right solution:

function isType<T>(this: ICustomElementResource, Type: T & { kind?: unknown }): Type is T & ICustomElementType {

@BBosman
Copy link
Contributor Author

BBosman commented Feb 23, 2019

@fkleuver I've found a solution that I'm happy with and that works.

If you could do another review when you've got a bit of time?

@fkleuver
Copy link
Member

@BBosman Overall it looks good but I'm not too fond of InstanceType<Constructable> since that's just a detour for its generic type argument (which is {} by default and we're trying to avoid this)

@BBosman
Copy link
Contributor Author

BBosman commented Feb 24, 2019

@fkleuver Valid comment. Did a bit of type refactoring and got rid of the InstanceType<Constructable>'s.

@fkleuver
Copy link
Member

Nice, thanks for fixing this up and apologies for the delay!

@fkleuver fkleuver merged commit 2e1e98a into master Feb 26, 2019
@fkleuver fkleuver deleted the typescript branch February 26, 2019 04:04
@BBosman BBosman mentioned this pull request Feb 26, 2019
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.

None yet

2 participants