-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Weak type detection #16047
Weak type detection #16047
Conversation
It's probably fine!
TODO: Report weak type errors for intersections *correctly*. That part's not done yet. Also, fix a couple of errors found by this change.
Plus add an intersection test case.
1. Accept baselines 2. Fix APISample_watcher 3. Switch checker to use JSDOc for isWeak Some of the baselines seem incorrect or weirder than before.
The Travis failure occurs because of an error in react.d.ts, which our tests have a copy of. |
Where's the head-desk emoji when you need it |
This even includes react.d.ts itself!
The weird test changes in controlFlowInstanceOf, subTypeReduction* and generatorTypeCheck63 are because subtype reduction has changed. So unions produce a different type when asked to do subtype reduction: { foo?: Foo } | { bar: Bar }
// used to reduce to
{ foo?: Foo }
// now it does not! I don't think it was supposed to work this way according to the spec, so this is an improvement. |
src/compiler/checker.ts
Outdated
return Ternary.False; | ||
} | ||
result &= related; | ||
} | ||
dynamicDisableWeakTypeErrors = saveDynamicDisableWeakTypeErrors; | ||
if (source !== globalObjectType && getPropertiesOfType(source).length > 0 && every(target.types, isWeak)) { |
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.
Comment on what you're doing here and below - the intent is obvious now, but it won't be to a random team member in 3 months. 😄
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 refactored this into a separate function and a named boolean. I think the two new names should serve as adequate documentation.
Summary of Real World Code runThere aren't as many errors as I thought -- 9, after the React fix in DefinitelyTyped. They are all very good errors except one questionable I will look at the errors from DefinitelyTyped next. GoodMisleading namesThere are two kinds of misleading names:
These are really hard to catch without the aid of a compiler. And Typescript wasn't checking assignability at all for weak targets. Now it catches the most egregious errors. This change found one instance of wishful thinking in VS Code and one instance of the namespace problem in another internal Microsoft project. (Who else would have four layers of legacy controls? (Don't answer that.)) Confusing typesThere are plenty of types which aren't assignable but look like they might be at first glance. For example: The compiler now catches more of these. It found 2 in VS Code, and 2 in 2 other internal Microsoft projects. Misleading
|
Summary of DefinitelyTyped runAgain, there are not as many errors as I thought. Of 3095 projects total, there were 20 errors in definition files and about 80 errors in test files. I haven't looked at the test files yet, but I didn't find any new error patterns in the definitions. Here's the breakdown: GoodMisleading namesWishful thinking: kendo-ui (3 times), react-leaflet, react-native Misleading
|
Fantastic. Those are much better results than I expected 👍 |
Yes, there are few enough errors that I am going to go fix up DefinitelyTyped right now. Note that the Ugly error pattern is very similar to one in the compiler I had to fix in this PR. |
This changes the definition of weak types
Previously, intersections disabled the weak type check for their constituents, and all properties (recursively) of their constituents. Also add test for this case.
What is the canonical recommended way of solving React-like false error? I.E. base class with all methods optional, derived class doesn't implement any of those optional methods. |
@mihailik class-interface merging. Remove the implements clause from the class declaration and add a line preceding it: interface C extends Optional {} |
So I thought this would get resolved upstream in I don't really want to wait a month for this, so I'm trying to figure out a way to deal with this in the meantime. What I don't understand about this
How does casting help me. This is an error in the typings themselves, not in my code. I'm guessing that in order to get this to compile, I'm going to have to go in and modify |
This is actually a problem with |
DefinitelyTyped/DefinitelyTyped#17581 will almost fix this. Unfortunately, the improved types expose another bug in This is a much simpler fix, though. I'll update palantir/blueprint#1237. |
Shouldn't this also prevent passing primitives as a parameter?
I know I can fix this by defining setup as |
@levenleven #16343 should have fixed this, but I don't think it shipped in the RC. Are you running 2.4.1 (the official release) or 2.4.0 (the RC). |
@sandersn Ok, thanks. Tried in playground, not sure which version is running there. |
Oops, I think the playground may still be running 2.3. @DanielRosenwasser did you update to 2.4 yet? Is it possible to add the version in small print when you do? |
I would like to define a type for "non-thenables". I was assuming the following would work:
However I get the "has no properties in common with" type error. After this change, how do I define a type for all values that do not have a |
type NotThenable = { then?: never; [others: string]: any } | number | string | boolean | symbol;
const x: NotThenable = 10;
const x1: NotThenable = {};
const x2: NotThenable = { m: 10 };
const x3: NotThenable = { then: () => null }; |
@RyanCavanaugh I was assuming |
I don't understand the question. What is |
Fixes #7485
Builds on #3842 by correctly handling intersections that contain weak types but may not necessarily be weak themselves. I ran the change on our real-world code corpus and on DefinitelyTyped and verified that it doesn't cause a huge number of breaks.
Weak types are
Weak types are common in Javascript, but the compiler allows almost anything to be assigned to them. The compiler misses a lot of obvious errors when you pass values to weakly typed parameters, implement weakly typed interfaces, or even cast to weak types. Here is an example of a weak type:
The weak type check occurs when the target is a weak type and the source has at least one property, call signature or construct signature. The weak type check issues an error if the source does not have any of the properties of the target. This is no longer allowed:
Intersection types are handled specially as weak type targets. Individual constituents of an intersection are exempt from the weak type check. However, if all constituents of an intersection are weak, then the weak type check uses the combined properties of the intersection as the target.
The global object type is handled specially as a weak type source. It is not an error to assign
Object
to a weak type, even if they don't share any properties. That's because people think ofObject
as similar to{}
, even though it actually includes a number of properties.This PR also improves errors for JSX attributes, which previously implemented their own weak type detection. It also improves subtype reduction because a weak type is no longer treated as a universal supertype like
{}
is.Edit: Update rules after some bug fixes.