-
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 #3842
Weak type detection #3842
Conversation
Note this would be a breaking change. |
👍 |
@RyanCavanaugh can we close this. |
Need to discuss at a design meeting to get a 👍 or 👎 on this |
What about this?
Would it show an error? |
@xLama that would not be an error due to the corresponding |
👍 |
Will this be in 1.6? |
Just encountered this: let intendedToBeANonPrimitive: { val1?: number, val2?: string };
intendedToBeANonPrimitive = 45.234234; // Works?! If the intention of the programmer was to allow the value to be assignable from a primitive, they would never have defined properties on it, either optional or required. If that was actually desirable, it is possible to use a union: let canAlsoBeANumber: { val1?: number, val2?: string } | number;
canAlsoBeANumber= 45.234234; // OK I encounter this problem very frequently with function "options" arguments, which are commonly defined to have all-optional properties. I frequently convert an old API that looks something like this: function getValues(startIndex?: number, endIndex?: number) To a new one accepting an function getValues(options: { startIndex?: number, endIndex?: number }) Then unexpectedly I don't get any error on incorrect calls like these: getValues(456); And have to track them manually. It would be great to have this fixed already in the 1.6 release. I personally consider this to be a bug. Anyway, keep up the great work :). |
That issue surfaces pretty badly when .d.ts authors order overloads incorrectly and order an overload taking a string after an overload taking an options bag. |
@DanielRosenwasser While I agree it's a bad problem, I don't think the overload ordering makes it that much worse because the initial pass of overload resolution uses subtype, not assignability. Subtype is tighter than assignability, and actually requires optional properties in the target to be present in the source, except when the source is an object literal. So a primitive, when passed to a function that expects an options bag, would fail subtype. |
One temporary workaround I gave a user was the following interface NoPrimitives {
valueOf?: { __DoNotUse: {} }; // Incompatible with 'valueOf' in strings, numbers, and booleans
test?: { __DoNotUse: {} }; // Incompatible with 'test' in regexes
}
interface Schema extends NoPrimitives {
type?: string;
items?: Schema | Schema[];
properties?: {[property: string]: Schema};
} |
This appears to have been closed without merging (or at least it doesn't appear to be working re: #7485). Was that intended? |
the issue still remains. the proposal is still under consideration, but there were no immediate plans to pursue it, that is why it is closed. |
Is there an issue with a proposal that is open? |
Not that i am aware of. @RyanCavanaugh ? |
Nope. |
I merged master with this PR and immediately found an incorrect argument being passed from checker. I'll create a new PR based on a branch in Microsoft/TypeScript when I get all the bugs fixed and tests passing. |
I found an additional case that we may not want to report errors for: class A { a? }
declare function foo(a: A): void;
function bar(faux: Object) {
foo(faux) // Error: Object doesn't have any properties in common with weak type A
} The author should have used The real example is more believable because class A { a? }
class B extends A { b }
declare function isB(a: A): a is B;
function bar(faux: Object) {
if (isB(faux)) { // Error: Object doesn't have any properties in common with weak type A
// sad code ... should have said `faux: A` or `isB(a: any)`
}
} |
This implements the other suggestion from @ahejlsberg in #3755, and fixes a compiler bug found by the rule (in editorServices.ts).
A weak type is one which has only optional properties and is not empty. Because these types are assignable from anything except types with matching non-assignable properties, they are very weakly typechecked. The simple fix here is to require that a type is only assignable to a weak type if they are not completely disjoint.
Example: