diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 07c20ad7aa0e9..aee85c6995421 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2285,7 +2285,7 @@ namespace ts { Debug.assert(typeNode !== undefined, "should always get typenode?"); const options = { removeComments: true }; const writer = createTextWriter(""); - const printer = createPrinter(options, writer); + const printer = createPrinter(options); const sourceFile = enclosingDeclaration && getSourceFileOfNode(enclosingDeclaration); printer.writeNode(EmitHint.Unspecified, typeNode, /*sourceFile*/ sourceFile, writer); const result = writer.getText(); @@ -8701,6 +8701,7 @@ namespace ts { let expandingFlags: number; let depth = 0; let overflow = false; + let isIntersectionConstituent = false; Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); @@ -8783,7 +8784,6 @@ namespace ts { * * Ternary.False if they are not related. */ function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary { - let result: Ternary; if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) { source = (source).regularType; } @@ -8815,32 +8815,39 @@ namespace ts { } } + if (!(source.flags & TypeFlags.UnionOrIntersection) && + !(target.flags & TypeFlags.Union) && + !isIntersectionConstituent && + source !== globalObjectType && + getPropertiesOfType(source).length > 0 && + isWeakType(target) && + !hasCommonProperties(source, target)) { + if (reportErrors) { + reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, typeToString(source), typeToString(target)); + } + return Ternary.False; + } + + let result = Ternary.False; const saveErrorInfo = errorInfo; + const saveIsIntersectionConstituent = isIntersectionConstituent; + isIntersectionConstituent = false; // Note that these checks are specifically ordered to produce correct results. In particular, // we need to deconstruct unions before intersections (because unions are always at the top), // and we need to handle "each" relations before "some" relations for the same kind of type. if (source.flags & TypeFlags.Union) { - if (relation === comparableRelation) { - result = someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)); - } - else { - result = eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)); - } - if (result) { - return result; - } + result = relation === comparableRelation ? + someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)) : + eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)); } else { if (target.flags & TypeFlags.Union) { - if (result = typeRelatedToSomeType(source, target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive))) { - return result; - } + result = typeRelatedToSomeType(source, target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive)); } else if (target.flags & TypeFlags.Intersection) { - if (result = typeRelatedToEachType(source, target as IntersectionType, reportErrors)) { - return result; - } + isIntersectionConstituent = true; + result = typeRelatedToEachType(source, target as IntersectionType, reportErrors); } else if (source.flags & TypeFlags.Intersection) { // Check to see if any constituents of the intersection are immediately related to the target. @@ -8856,20 +8863,18 @@ namespace ts { // // - For a primitive type or type parameter (such as 'number = A & B') there is no point in // breaking the intersection apart. - if (result = someTypeRelatedToType(source, target, /*reportErrors*/ false)) { - return result; - } + result = someTypeRelatedToType(source, target, /*reportErrors*/ false); } - - if (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable) { + if (!result && (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable)) { if (result = recursiveTypeRelatedTo(source, target, reportErrors)) { errorInfo = saveErrorInfo; - return result; } } } - if (reportErrors) { + isIntersectionConstituent = saveIsIntersectionConstituent; + + if (!result && reportErrors) { if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) { tryElaborateErrorsForPrimitivesAndObjects(source, target); } @@ -8878,7 +8883,7 @@ namespace ts { } reportRelationError(headMessage, source, target); } - return Ternary.False; + return result; } function isIdenticalTo(source: Type, target: Type): Ternary { @@ -8977,7 +8982,7 @@ namespace ts { } } - function typeRelatedToEachType(source: Type, target: UnionOrIntersectionType, reportErrors: boolean): Ternary { + function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean): Ternary { let result = Ternary.True; const targetTypes = target.types; for (const targetType of targetTypes) { @@ -9279,7 +9284,6 @@ namespace ts { const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral); for (const targetProp of properties) { const sourceProp = getPropertyOfType(source, targetProp.name); - if (sourceProp !== targetProp) { if (!sourceProp) { if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) { @@ -9358,6 +9362,34 @@ namespace ts { return result; } + /** + * A type is 'weak' if it is an object type with at least one optional property + * and no required properties, call/construct signatures or index signatures + */ + function isWeakType(type: Type): boolean { + if (type.flags & TypeFlags.Object) { + const resolved = resolveStructuredTypeMembers(type); + return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && + !resolved.stringIndexInfo && !resolved.numberIndexInfo && + resolved.properties.length > 0 && + every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional)); + } + if (type.flags & TypeFlags.Intersection) { + return every((type).types, isWeakType); + } + return false; + } + + function hasCommonProperties(source: Type, target: Type) { + const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes); + for (const prop of getPropertiesOfType(source)) { + if (isKnownProperty(target, prop.name, isComparingJsxAttributes)) { + return true; + } + } + return false; + } + function propertiesIdenticalTo(source: Type, target: Type): Ternary { if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) { return Ternary.False; @@ -14121,8 +14153,10 @@ namespace ts { function isKnownProperty(targetType: Type, name: string, isComparingJsxAttributes: boolean): boolean { if (targetType.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(targetType); - if (resolved.stringIndexInfo || resolved.numberIndexInfo && isNumericLiteralName(name) || - getPropertyOfType(targetType, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) { + if (resolved.stringIndexInfo || + resolved.numberIndexInfo && isNumericLiteralName(name) || + getPropertyOfType(targetType, name) || + isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) { // For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known. return true; } @@ -22671,12 +22705,12 @@ namespace ts { return symbols; } else if (symbol.flags & SymbolFlags.Transient) { - if ((symbol as SymbolLinks).leftSpread) { - const links = symbol as SymbolLinks; - return [...getRootSymbols(links.leftSpread), ...getRootSymbols(links.rightSpread)]; + const transient = symbol as TransientSymbol; + if (transient.leftSpread) { + return [...getRootSymbols(transient.leftSpread), ...getRootSymbols(transient.rightSpread)]; } - if ((symbol as SymbolLinks).syntheticOrigin) { - return getRootSymbols((symbol as SymbolLinks).syntheticOrigin); + if (transient.syntheticOrigin) { + return getRootSymbols(transient.syntheticOrigin); } let target: Symbol; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index a7b6db70e5e57..e8ad8a033ffa9 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1879,6 +1879,10 @@ "category": "Error", "code": 2558 }, + "Type '{0}' has no properties in common with type '{1}'.": { + "category": "Error", + "code": 2559 + }, "JSX element attributes type '{0}' may not be a union type.": { "category": "Error", "code": 2600 diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index b813a44f53e3c..f4d03f8f62fe3 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -11,7 +11,7 @@ declare var fs: { existsSync(path: string): boolean; readdirSync(path: string): string[]; readFileSync(filename: string, encoding?: string): string; - writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; + writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; } | string): void; watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: { mtime: Date }, prev: { mtime: Date }) => void): void; }; declare var path: any; diff --git a/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.errors.txt b/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.errors.txt index de2751beacaba..0d7fe1071e919 100644 --- a/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.errors.txt +++ b/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.errors.txt @@ -1,3 +1,12 @@ +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(33,5): error TS2559: Type 'D' has no properties in common with type 'C'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(34,5): error TS2559: Type 'E' has no properties in common with type 'C'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(35,5): error TS2559: Type 'F' has no properties in common with type 'C'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(36,5): error TS2559: Type 'D' has no properties in common with type '{ opt?: Base; }'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(37,5): error TS2559: Type 'E' has no properties in common with type '{ opt?: Base; }'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(38,5): error TS2559: Type 'F' has no properties in common with type '{ opt?: Base; }'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(39,5): error TS2559: Type 'D' has no properties in common with type '{ opt?: Base; }'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(40,5): error TS2559: Type 'E' has no properties in common with type '{ opt?: Base; }'. +tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(41,5): error TS2559: Type 'F' has no properties in common with type '{ opt?: Base; }'. tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(74,5): error TS2322: Type 'D' is not assignable to type 'C'. Property 'opt' is missing in type 'D'. tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts(75,5): error TS2322: Type 'E' is not assignable to type 'C'. @@ -18,7 +27,7 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme Property 'opt' is missing in type 'F'. -==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts (9 errors) ==== +==== tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts (18 errors) ==== // M is optional and S contains no property with the same name as M // N is optional and T contains no property with the same name as N @@ -50,20 +59,38 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme var e: E; var f: F; - // all ok + // disallowed by weak type checking c = d; + ~ +!!! error TS2559: Type 'D' has no properties in common with type 'C'. c = e; + ~ +!!! error TS2559: Type 'E' has no properties in common with type 'C'. c = f; - c = a; - + ~ +!!! error TS2559: Type 'F' has no properties in common with type 'C'. a = d; + ~ +!!! error TS2559: Type 'D' has no properties in common with type '{ opt?: Base; }'. a = e; + ~ +!!! error TS2559: Type 'E' has no properties in common with type '{ opt?: Base; }'. a = f; - a = c; - + ~ +!!! error TS2559: Type 'F' has no properties in common with type '{ opt?: Base; }'. b = d; + ~ +!!! error TS2559: Type 'D' has no properties in common with type '{ opt?: Base; }'. b = e; + ~ +!!! error TS2559: Type 'E' has no properties in common with type '{ opt?: Base; }'. b = f; + ~ +!!! error TS2559: Type 'F' has no properties in common with type '{ opt?: Base; }'. + + // ok + c = a; + a = c; b = a; b = c; } @@ -134,4 +161,5 @@ tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignme !!! error TS2322: Property 'opt' is missing in type 'F'. b = a; // ok b = c; // ok - } \ No newline at end of file + } + \ No newline at end of file diff --git a/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.js b/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.js index e158a78787883..d83f3182531ed 100644 --- a/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.js +++ b/tests/baselines/reference/assignmentCompatWithObjectMembersOptionality2.js @@ -30,20 +30,20 @@ module TargetHasOptional { var e: E; var f: F; - // all ok + // disallowed by weak type checking c = d; c = e; c = f; - c = a; - a = d; a = e; a = f; - a = c; - b = d; b = e; b = f; + + // ok + c = a; + a = c; b = a; b = c; } @@ -87,7 +87,8 @@ module SourceHasOptional { b = f; // error b = a; // ok b = c; // ok -} +} + //// [assignmentCompatWithObjectMembersOptionality2.js] // M is optional and S contains no property with the same name as M @@ -129,18 +130,19 @@ var TargetHasOptional; var d; var e; var f; - // all ok + // disallowed by weak type checking c = d; c = e; c = f; - c = a; a = d; a = e; a = f; - a = c; b = d; b = e; b = f; + // ok + c = a; + a = c; b = a; b = c; })(TargetHasOptional || (TargetHasOptional = {})); diff --git a/tests/baselines/reference/checkJsxChildrenProperty1.symbols b/tests/baselines/reference/checkJsxChildrenProperty1.symbols index 8793d0edd496d..ede60746f4bf8 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty1.symbols +++ b/tests/baselines/reference/checkJsxChildrenProperty1.symbols @@ -13,8 +13,8 @@ interface Prop { children: string | JSX.Element >children : Symbol(Prop.children, Decl(file.tsx, 4, 14)) ->JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) ->Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27)) } function Comp(p: Prop) { @@ -23,11 +23,11 @@ function Comp(p: Prop) { >Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) return
{p.b}
; ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) >p.b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) >p : Symbol(p, Decl(file.tsx, 8, 14)) >b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) } // OK @@ -59,8 +59,8 @@ let k2 = >b : Symbol(b, Decl(file.tsx, 19, 16))
hi hi hi!
->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) ; >Comp : Symbol(Comp, Decl(file.tsx, 6, 1)) diff --git a/tests/baselines/reference/checkJsxChildrenProperty12.symbols b/tests/baselines/reference/checkJsxChildrenProperty12.symbols index ccfb4b18875a0..09080234ea930 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty12.symbols +++ b/tests/baselines/reference/checkJsxChildrenProperty12.symbols @@ -18,9 +18,9 @@ interface ButtonProp { class Button extends React.Component { >Button : Symbol(Button, Decl(file.tsx, 6, 1)) ->React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >React : Symbol(React, Decl(file.tsx, 0, 0)) ->Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >ButtonProp : Symbol(ButtonProp, Decl(file.tsx, 0, 32)) render() { @@ -34,20 +34,20 @@ class Button extends React.Component { return >InnerButton : Symbol(InnerButton, Decl(file.tsx, 24, 1)) ->this.props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>this.props : Symbol(React.Component.props, Decl(react.d.ts, 167, 37)) >this : Symbol(Button, Decl(file.tsx, 6, 1)) ->props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>props : Symbol(React.Component.props, Decl(react.d.ts, 167, 37)) } else { return ( >InnerButton : Symbol(InnerButton, Decl(file.tsx, 24, 1)) ->this.props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>this.props : Symbol(React.Component.props, Decl(react.d.ts, 167, 37)) >this : Symbol(Button, Decl(file.tsx, 6, 1)) ->props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>props : Symbol(React.Component.props, Decl(react.d.ts, 167, 37))
Hello World
->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
); >InnerButton : Symbol(InnerButton, Decl(file.tsx, 24, 1)) @@ -64,17 +64,17 @@ interface InnerButtonProp { class InnerButton extends React.Component { >InnerButton : Symbol(InnerButton, Decl(file.tsx, 24, 1)) ->React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >React : Symbol(React, Decl(file.tsx, 0, 0)) ->Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >InnerButtonProp : Symbol(InnerButtonProp, Decl(file.tsx, 20, 1)) render() { >render : Symbol(InnerButton.render, Decl(file.tsx, 26, 65)) return (); ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2386, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2386, 43)) } } diff --git a/tests/baselines/reference/checkJsxChildrenProperty3.symbols b/tests/baselines/reference/checkJsxChildrenProperty3.symbols index 49d146f07dac4..ea1beff75ac56 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty3.symbols +++ b/tests/baselines/reference/checkJsxChildrenProperty3.symbols @@ -16,34 +16,34 @@ interface IFetchUserProps { >children : Symbol(IFetchUserProps.children, Decl(file.tsx, 6, 27)) >user : Symbol(user, Decl(file.tsx, 7, 15)) >IUser : Symbol(IUser, Decl(file.tsx, 0, 32)) ->JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) ->Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27)) } class FetchUser extends React.Component { >FetchUser : Symbol(FetchUser, Decl(file.tsx, 8, 1)) ->React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >React : Symbol(React, Decl(file.tsx, 0, 0)) ->Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >IFetchUserProps : Symbol(IFetchUserProps, Decl(file.tsx, 4, 1)) render() { >render : Symbol(FetchUser.render, Decl(file.tsx, 10, 63)) return this.state ->this.state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) +>this.state : Symbol(React.Component.state, Decl(react.d.ts, 174, 44)) >this : Symbol(FetchUser, Decl(file.tsx, 8, 1)) ->state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) +>state : Symbol(React.Component.state, Decl(react.d.ts, 174, 44)) ? this.props.children(this.state.result) ->this.props.children : Symbol(children, Decl(file.tsx, 6, 27), Decl(react.d.ts, 173, 20)) ->this.props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) +>this.props.children : Symbol(children, Decl(file.tsx, 6, 27), Decl(react.d.ts, 174, 20)) +>this.props : Symbol(React.Component.props, Decl(react.d.ts, 167, 37)) >this : Symbol(FetchUser, Decl(file.tsx, 8, 1)) ->props : Symbol(React.Component.props, Decl(react.d.ts, 166, 37)) ->children : Symbol(children, Decl(file.tsx, 6, 27), Decl(react.d.ts, 173, 20)) ->this.state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) +>props : Symbol(React.Component.props, Decl(react.d.ts, 167, 37)) +>children : Symbol(children, Decl(file.tsx, 6, 27), Decl(react.d.ts, 174, 20)) +>this.state : Symbol(React.Component.state, Decl(react.d.ts, 174, 44)) >this : Symbol(FetchUser, Decl(file.tsx, 8, 1)) ->state : Symbol(React.Component.state, Decl(react.d.ts, 173, 44)) +>state : Symbol(React.Component.state, Decl(react.d.ts, 174, 44)) : null; } @@ -61,11 +61,11 @@ function UserName0() { >user : Symbol(user, Decl(file.tsx, 22, 13))

{ user.Name }

->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) >user.Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) >user : Symbol(user, Decl(file.tsx, 22, 13)) >Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) ) } @@ -85,11 +85,11 @@ function UserName1() { >user : Symbol(user, Decl(file.tsx, 33, 13))

{ user.Name }

->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) >user.Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) >user : Symbol(user, Decl(file.tsx, 33, 13)) >Name : Symbol(IUser.Name, Decl(file.tsx, 2, 17)) ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) ) } diff --git a/tests/baselines/reference/checkJsxChildrenProperty6.symbols b/tests/baselines/reference/checkJsxChildrenProperty6.symbols index e69b24a89ab22..3fc70d4188361 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty6.symbols +++ b/tests/baselines/reference/checkJsxChildrenProperty6.symbols @@ -13,24 +13,24 @@ interface Prop { children: JSX.Element | JSX.Element[]; >children : Symbol(Prop.children, Decl(file.tsx, 4, 14)) ->JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) ->Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) ->JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) ->Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27)) } class Button extends React.Component { >Button : Symbol(Button, Decl(file.tsx, 6, 1)) ->React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >React : Symbol(React, Decl(file.tsx, 0, 0)) ->Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) render() { >render : Symbol(Button.render, Decl(file.tsx, 8, 48)) return (
My Button
) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) } } @@ -39,8 +39,8 @@ function AnotherButton(p: any) { >p : Symbol(p, Decl(file.tsx, 14, 23)) return

Just Another Button

; ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) } function Comp(p: Prop) { @@ -49,11 +49,11 @@ function Comp(p: Prop) { >Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) return
{p.b}
; ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) >p.b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) >p : Symbol(p, Decl(file.tsx, 18, 14)) >b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) } // Ok diff --git a/tests/baselines/reference/checkJsxChildrenProperty8.symbols b/tests/baselines/reference/checkJsxChildrenProperty8.symbols index b6f5f97adac23..3d2e232203bf0 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty8.symbols +++ b/tests/baselines/reference/checkJsxChildrenProperty8.symbols @@ -13,24 +13,24 @@ interface Prop { children: string | JSX.Element | (string | JSX.Element)[]; >children : Symbol(Prop.children, Decl(file.tsx, 4, 14)) ->JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) ->Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) ->JSX : Symbol(JSX, Decl(react.d.ts, 2352, 1)) ->Element : Symbol(JSX.Element, Decl(react.d.ts, 2355, 27)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27)) +>JSX : Symbol(JSX, Decl(react.d.ts, 2353, 1)) +>Element : Symbol(JSX.Element, Decl(react.d.ts, 2356, 27)) } class Button extends React.Component { >Button : Symbol(Button, Decl(file.tsx, 6, 1)) ->React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >React : Symbol(React, Decl(file.tsx, 0, 0)) ->Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) render() { >render : Symbol(Button.render, Decl(file.tsx, 8, 48)) return (
My Button
) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) } } @@ -39,8 +39,8 @@ function AnotherButton(p: any) { >p : Symbol(p, Decl(file.tsx, 14, 23)) return

Just Another Button

; ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) } function Comp(p: Prop) { @@ -49,11 +49,11 @@ function Comp(p: Prop) { >Prop : Symbol(Prop, Decl(file.tsx, 0, 32)) return
{p.b}
; ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) >p.b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) >p : Symbol(p, Decl(file.tsx, 18, 14)) >b : Symbol(Prop.b, Decl(file.tsx, 3, 14)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) } // OK diff --git a/tests/baselines/reference/checkJsxChildrenProperty9.symbols b/tests/baselines/reference/checkJsxChildrenProperty9.symbols index 25a32aae695f8..147fc4939f5dc 100644 --- a/tests/baselines/reference/checkJsxChildrenProperty9.symbols +++ b/tests/baselines/reference/checkJsxChildrenProperty9.symbols @@ -5,26 +5,26 @@ import React = require('react'); // OK let k1 =

Hello

world

; >k1 : Symbol(k1, Decl(file.tsx, 3, 3)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) ->h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2410, 48)) ->h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2410, 48)) ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) ->h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2409, 47)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2411, 48)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2411, 48)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) +>h1 : Symbol(JSX.IntrinsicElements.h1, Decl(react.d.ts, 2410, 47)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) let k2 =

Hello

{(user: any) =>

{user.name}

}
; >k2 : Symbol(k2, Decl(file.tsx, 4, 3)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) ->h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2410, 48)) ->h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2410, 48)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2411, 48)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2411, 48)) >user : Symbol(user, Decl(file.tsx, 4, 34)) ->h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2410, 48)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2411, 48)) >user : Symbol(user, Decl(file.tsx, 4, 34)) ->h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2410, 48)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>h2 : Symbol(JSX.IntrinsicElements.h2, Decl(react.d.ts, 2411, 48)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) let k3 =
{1} {"That is a number"}
; >k3 : Symbol(k3, Decl(file.tsx, 5, 3)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) diff --git a/tests/baselines/reference/commentEmittingInPreserveJsx1.symbols b/tests/baselines/reference/commentEmittingInPreserveJsx1.symbols index 43d833e27b19d..9accc8af0b6b6 100644 --- a/tests/baselines/reference/commentEmittingInPreserveJsx1.symbols +++ b/tests/baselines/reference/commentEmittingInPreserveJsx1.symbols @@ -3,14 +3,14 @@ import React = require('react'); >React : Symbol(React, Decl(file.tsx, 0, 0))
->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) // Not Comment
; ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) // Not Comment { @@ -18,10 +18,10 @@ import React = require('react'); } // Another not Comment
; ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) // Not Comment { @@ -30,10 +30,10 @@ import React = require('react'); } // Another not Comment
; ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) /* Not Comment */ { @@ -41,5 +41,5 @@ import React = require('react'); "Hi" }
; ->div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2399, 45)) +>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45)) diff --git a/tests/baselines/reference/controlFlowInstanceof.types b/tests/baselines/reference/controlFlowInstanceof.types index 16d1ec71462f0..5b9ea793e7de3 100644 --- a/tests/baselines/reference/controlFlowInstanceof.types +++ b/tests/baselines/reference/controlFlowInstanceof.types @@ -247,7 +247,7 @@ function goo(x: X) { x.y; >x.y : string ->x : Y +>x : X & Y >y : string } x; diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols b/tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols index 3267a29050e11..b0338f1c803f8 100644 --- a/tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences1.symbols @@ -11,17 +11,17 @@ let buttonProps; // any let k = ; ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2386, 43)) === tests/cases/conformance/jsx/declaration.d.ts === declare module "classnames"; diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols b/tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols index 76d9b8cdfe076..7e131bde87807 100644 --- a/tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences2.symbols @@ -12,17 +12,17 @@ let buttonProps : {[attributeName: string]: ''} let k = ; ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2386, 43)) === tests/cases/conformance/jsx/declaration.d.ts === declare module "classnames"; diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols b/tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols index 088f553baa495..4002c29b3c67e 100644 --- a/tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences3.symbols @@ -11,17 +11,17 @@ let buttonProps; let k = ; ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2386, 43)) === tests/cases/conformance/jsx/declaration.d.ts === declare module "classnames"; diff --git a/tests/baselines/reference/correctlyMarkAliasAsReferences4.symbols b/tests/baselines/reference/correctlyMarkAliasAsReferences4.symbols index 83b245072e91a..0253e34533f4d 100644 --- a/tests/baselines/reference/correctlyMarkAliasAsReferences4.symbols +++ b/tests/baselines/reference/correctlyMarkAliasAsReferences4.symbols @@ -12,7 +12,7 @@ let buttonProps : {[attributeName: string]: ''} let k = }/> >MyComponent : Symbol(MyComponent, Decl(file.tsx, 4, 1)) >AnyComponent : Symbol(AnyComponent, Decl(file.tsx, 14, 12)) ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) ->button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2385, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2386, 43)) +>button : Symbol(JSX.IntrinsicElements.button, Decl(react.d.ts, 2386, 43)) // Component Class as Props class MyButtonComponent extends React.Component<{},{}> { >MyButtonComponent : Symbol(MyButtonComponent, Decl(file.tsx, 14, 57)) ->React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>React.Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) >React : Symbol(React, Decl(file.tsx, 0, 0)) ->Component : Symbol(React.Component, Decl(react.d.ts, 158, 55)) +>Component : Symbol(React.Component, Decl(react.d.ts, 158, 55), Decl(react.d.ts, 161, 66)) } diff --git a/tests/baselines/reference/weakType.errors.txt b/tests/baselines/reference/weakType.errors.txt new file mode 100644 index 0000000000000..7064ace5daaaa --- /dev/null +++ b/tests/baselines/reference/weakType.errors.txt @@ -0,0 +1,72 @@ +tests/cases/compiler/weakType.ts(31,18): error TS2559: Type '{ error?: number; }' has no properties in common with type 'ChangeOptions'. +tests/cases/compiler/weakType.ts(56,5): error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'. + Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak'. + Types of property 'properties' are incompatible. + Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'. + + +==== tests/cases/compiler/weakType.ts (2 errors) ==== + interface Settings { + timeout?: number; + onError?(): void; + } + + function getDefaultSettings() { + return { timeout: 1000 }; + } + + function doSomething(settings: Settings) { /* ... */ } + + // forgot to call `getDefaultSettings` + // but it is not caught because we don't check for call signatures + doSomething(getDefaultSettings); + + // this is an oddly popular way of defining settings + // this example is from services/textChanges.ts + type ConfigurableStart = { useStart?: boolean } + type ConfigurableEnd = { useEnd?: boolean } + type ConfigurableStartEnd = ConfigurableStart & ConfigurableEnd + interface InsertOptions { + prefix?: string + suffix?: string + } + type ChangeOptions = ConfigurableStartEnd & InsertOptions; + + function del(options: ConfigurableStartEnd = {}, + error: { error?: number } = {}) { + let changes: ChangeOptions[]; + changes.push(options); + changes.push(error); + ~~~~~ +!!! error TS2559: Type '{ error?: number; }' has no properties in common with type 'ChangeOptions'. + } + + class K { + constructor(s: string) { } + } + // Ctor isn't a weak type because it has a construct signature + interface Ctor { + new (s: string): K + n?: number + } + let ctor: Ctor = K + + type Spoiler = { nope?: string } + type Weak = { + a?: number + properties?: { + b?: number + } + } + declare let unknown: { + properties: { + wrong: string + } + } + let weak: Weak & Spoiler = unknown + ~~~~ +!!! error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak & Spoiler'. +!!! error TS2322: Type '{ properties: { wrong: string; }; }' is not assignable to type 'Weak'. +!!! error TS2322: Types of property 'properties' are incompatible. +!!! error TS2322: Type '{ wrong: string; }' has no properties in common with type '{ b?: number; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/weakType.js b/tests/baselines/reference/weakType.js new file mode 100644 index 0000000000000..6ed3ff1814df9 --- /dev/null +++ b/tests/baselines/reference/weakType.js @@ -0,0 +1,81 @@ +//// [weakType.ts] +interface Settings { + timeout?: number; + onError?(): void; +} + +function getDefaultSettings() { + return { timeout: 1000 }; +} + +function doSomething(settings: Settings) { /* ... */ } + +// forgot to call `getDefaultSettings` +// but it is not caught because we don't check for call signatures +doSomething(getDefaultSettings); + +// this is an oddly popular way of defining settings +// this example is from services/textChanges.ts +type ConfigurableStart = { useStart?: boolean } +type ConfigurableEnd = { useEnd?: boolean } +type ConfigurableStartEnd = ConfigurableStart & ConfigurableEnd +interface InsertOptions { + prefix?: string + suffix?: string +} +type ChangeOptions = ConfigurableStartEnd & InsertOptions; + +function del(options: ConfigurableStartEnd = {}, + error: { error?: number } = {}) { + let changes: ChangeOptions[]; + changes.push(options); + changes.push(error); +} + +class K { + constructor(s: string) { } +} +// Ctor isn't a weak type because it has a construct signature +interface Ctor { + new (s: string): K + n?: number +} +let ctor: Ctor = K + +type Spoiler = { nope?: string } +type Weak = { + a?: number + properties?: { + b?: number + } +} +declare let unknown: { + properties: { + wrong: string + } +} +let weak: Weak & Spoiler = unknown + + +//// [weakType.js] +function getDefaultSettings() { + return { timeout: 1000 }; +} +function doSomething(settings) { } +// forgot to call `getDefaultSettings` +// but it is not caught because we don't check for call signatures +doSomething(getDefaultSettings); +function del(options, error) { + if (options === void 0) { options = {}; } + if (error === void 0) { error = {}; } + var changes; + changes.push(options); + changes.push(error); +} +var K = (function () { + function K(s) { + } + return K; +}()); +var ctor = K; +var weak = unknown; diff --git a/tests/cases/compiler/APISample_watcher.ts b/tests/cases/compiler/APISample_watcher.ts index 3e8ce3d8d63e2..436a1401d575c 100644 --- a/tests/cases/compiler/APISample_watcher.ts +++ b/tests/cases/compiler/APISample_watcher.ts @@ -15,7 +15,7 @@ declare var fs: { existsSync(path: string): boolean; readdirSync(path: string): string[]; readFileSync(filename: string, encoding?: string): string; - writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; + writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; } | string): void; watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: { mtime: Date }, prev: { mtime: Date }) => void): void; }; declare var path: any; diff --git a/tests/cases/compiler/weakType.ts b/tests/cases/compiler/weakType.ts new file mode 100644 index 0000000000000..f04f36c9c2f9e --- /dev/null +++ b/tests/cases/compiler/weakType.ts @@ -0,0 +1,56 @@ +interface Settings { + timeout?: number; + onError?(): void; +} + +function getDefaultSettings() { + return { timeout: 1000 }; +} + +function doSomething(settings: Settings) { /* ... */ } + +// forgot to call `getDefaultSettings` +// but it is not caught because we don't check for call signatures +doSomething(getDefaultSettings); + +// this is an oddly popular way of defining settings +// this example is from services/textChanges.ts +type ConfigurableStart = { useStart?: boolean } +type ConfigurableEnd = { useEnd?: boolean } +type ConfigurableStartEnd = ConfigurableStart & ConfigurableEnd +interface InsertOptions { + prefix?: string + suffix?: string +} +type ChangeOptions = ConfigurableStartEnd & InsertOptions; + +function del(options: ConfigurableStartEnd = {}, + error: { error?: number } = {}) { + let changes: ChangeOptions[]; + changes.push(options); + changes.push(error); +} + +class K { + constructor(s: string) { } +} +// Ctor isn't a weak type because it has a construct signature +interface Ctor { + new (s: string): K + n?: number +} +let ctor: Ctor = K + +type Spoiler = { nope?: string } +type Weak = { + a?: number + properties?: { + b?: number + } +} +declare let unknown: { + properties: { + wrong: string + } +} +let weak: Weak & Spoiler = unknown diff --git a/tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx b/tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx index a9466a43983f7..32a1af66f8441 100644 --- a/tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx +++ b/tests/cases/conformance/jsx/tsxGenericAttributesType9.tsx @@ -5,7 +5,7 @@ import React = require('react'); -export function makeP

(Ctor: React.ComponentClass

): React.ComponentClass

{ +export function makeP

(Ctor: React.ComponentClass

) { return class extends React.PureComponent { public render(): JSX.Element { return ( @@ -13,4 +13,5 @@ export function makeP

(Ctor: React.ComponentClass

): React.ComponentClass

); } }; -} \ No newline at end of file +} + diff --git a/tests/cases/conformance/jsx/tsxStatelessFunctionComponentOverload1.tsx b/tests/cases/conformance/jsx/tsxStatelessFunctionComponentOverload1.tsx index d8897321f0b3d..525d035cbfec9 100644 --- a/tests/cases/conformance/jsx/tsxStatelessFunctionComponentOverload1.tsx +++ b/tests/cases/conformance/jsx/tsxStatelessFunctionComponentOverload1.tsx @@ -38,10 +38,10 @@ declare function TestingOptional(a: {y1: boolean, y2?: number, y3: boolean}): JS // OK const e1 = -const e2 = const e3 = const e4 = const e5 = const e6 = +const e2 = diff --git a/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts b/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts index 11b32abdf5040..1f19328568141 100644 --- a/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts +++ b/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithObjectMembersOptionality2.ts @@ -29,20 +29,20 @@ module TargetHasOptional { var e: E; var f: F; - // all ok + // disallowed by weak type checking c = d; c = e; c = f; - c = a; - a = d; a = e; a = f; - a = c; - b = d; b = e; b = f; + + // ok + c = a; + a = c; b = a; b = c; } @@ -86,4 +86,4 @@ module SourceHasOptional { b = f; // error b = a; // ok b = c; // ok -} \ No newline at end of file +} diff --git a/tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithObjectMembers5.ts b/tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithObjectMembers5.ts index 9a83bb660f8d1..1095a2183f392 100644 --- a/tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithObjectMembers5.ts +++ b/tests/cases/conformance/types/typeRelationships/subtypesAndSuperTypes/subtypingWithObjectMembers5.ts @@ -41,7 +41,7 @@ module Optional { } class B implements A { - fooo: Derived; // ok + fooo: Derived; // weak type error } interface A2 { @@ -49,7 +49,7 @@ module Optional { } class B2 implements A2 { - 2: Derived; // ok + 2: Derived; // weak type error } interface A3 { @@ -57,6 +57,6 @@ module Optional { } class B3 implements A3 { - '1.0': Derived; // ok + '1.0': Derived; // weak type error } -} \ No newline at end of file +} diff --git a/tests/lib/react.d.ts b/tests/lib/react.d.ts index 7f03899eb6c6a..aead9f9f23c38 100644 --- a/tests/lib/react.d.ts +++ b/tests/lib/react.d.ts @@ -159,7 +159,8 @@ declare namespace __React { type ReactInstance = Component | Element; // Base component for plain JS classes - class Component implements ComponentLifecycle { + interface Component extends ComponentLifecycle { } + class Component { constructor(props?: P, context?: any); setState(f: (prevState: S, props: P) => S, callback?: () => any): void; setState(state: S, callback?: () => any): void;