diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aaaa0ed50b88c..72438fa27af87 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -260,6 +260,7 @@ namespace ts { const literalTypes = createMap(); const indexedAccessTypes = createMap(); const evolvingArrayTypes: EvolvingArrayType[] = []; + const undefinedProperties = createMap() as UnderscoreEscapedMap; const unknownSymbol = createSymbol(SymbolFlags.Property, "unknown" as __String); const resolvingSymbol = createSymbol(0, InternalSymbolName.Resolving); @@ -7984,7 +7985,7 @@ namespace ts { const spread = createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); spread.flags |= propagatedFlags; spread.flags |= TypeFlags.FreshLiteral | TypeFlags.ContainsObjectLiteral; - (spread as ObjectType).objectFlags |= ObjectFlags.ObjectLiteral; + (spread as ObjectType).objectFlags |= (ObjectFlags.ObjectLiteral | ObjectFlags.ContainsSpread); spread.symbol = symbol; return spread; } @@ -9026,7 +9027,7 @@ namespace ts { if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True; - if (getObjectFlags(source) & ObjectFlags.ObjectLiteral && source.flags & TypeFlags.FreshLiteral) { + if (isObjectLiteralType(source) && source.flags & TypeFlags.FreshLiteral) { if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { reportRelationError(headMessage, source, target); @@ -9596,7 +9597,7 @@ namespace ts { if (relation === identityRelation) { return propertiesIdenticalTo(source, target); } - const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral); + const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source); const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties); if (unmatchedProperty) { if (reportErrors) { @@ -9604,6 +9605,19 @@ namespace ts { } return Ternary.False; } + if (isObjectLiteralType(target)) { + for (const sourceProp of getPropertiesOfType(source)) { + if (!getPropertyOfObjectType(target, sourceProp.escapedName)) { + const sourceType = getTypeOfSymbol(sourceProp); + if (!(sourceType === undefinedType || sourceType === undefinedWideningType)) { + if (reportErrors) { + reportError(Diagnostics.Property_0_does_not_exist_on_type_1, symbolToString(sourceProp), typeToString(target)); + } + return Ternary.False; + } + } + } + } let result = Ternary.True; const properties = getPropertiesOfObjectType(target); for (const targetProp of properties) { @@ -10425,7 +10439,7 @@ namespace ts { * Leave signatures alone since they are not subject to the check. */ function getRegularTypeOfObjectLiteral(type: Type): Type { - if (!(getObjectFlags(type) & ObjectFlags.ObjectLiteral && type.flags & TypeFlags.FreshLiteral)) { + if (!(isObjectLiteralType(type) && type.flags & TypeFlags.FreshLiteral)) { return type; } const regularType = (type).regularType; @@ -10447,18 +10461,74 @@ namespace ts { return regularNew; } - function getWidenedProperty(prop: Symbol): Symbol { + function createWideningContext(parent: WideningContext, propertyName: __String, siblings: Type[]): WideningContext { + return { parent, propertyName, siblings, resolvedPropertyNames: undefined }; + } + + function getSiblingsOfContext(context: WideningContext): Type[] { + if (!context.siblings) { + const siblings: Type[] = []; + for (const type of getSiblingsOfContext(context.parent)) { + if (isObjectLiteralType(type)) { + const prop = getPropertyOfObjectType(type, context.propertyName); + if (prop) { + forEachType(getTypeOfSymbol(prop), t => { + siblings.push(t); + }); + } + } + } + context.siblings = siblings; + } + return context.siblings; + } + + function getPropertyNamesOfContext(context: WideningContext): __String[] { + if (!context.resolvedPropertyNames) { + const names = createMap() as UnderscoreEscapedMap; + for (const t of getSiblingsOfContext(context)) { + if (isObjectLiteralType(t) && !(getObjectFlags(t) & ObjectFlags.ContainsSpread)) { + for (const prop of getPropertiesOfType(t)) { + names.set(prop.escapedName, true); + } + } + } + context.resolvedPropertyNames = arrayFrom(names.keys()); + } + return context.resolvedPropertyNames; + } + + function getWidenedProperty(prop: Symbol, context: WideningContext): Symbol { const original = getTypeOfSymbol(prop); - const widened = getWidenedType(original); + const propContext = context && createWideningContext(context, prop.escapedName, /*siblings*/ undefined); + const widened = getWidenedTypeWithContext(original, propContext); return widened === original ? prop : createSymbolWithType(prop, widened); } - function getWidenedTypeOfObjectLiteral(type: Type): Type { + function getUndefinedProperty(name: __String) { + const cached = undefinedProperties.get(name); + if (cached) { + return cached; + } + const result = createSymbol(SymbolFlags.Property | SymbolFlags.Optional, name); + result.type = undefinedType; + undefinedProperties.set(name, result); + return result; + } + + function getWidenedTypeOfObjectLiteral(type: Type, context: WideningContext): Type { const members = createSymbolTable(); for (const prop of getPropertiesOfObjectType(type)) { // Since get accessors already widen their return value there is no need to // widen accessor based properties here. - members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop) : prop); + members.set(prop.escapedName, prop.flags & SymbolFlags.Property ? getWidenedProperty(prop, context) : prop); + } + if (context) { + for (const name of getPropertyNamesOfContext(context)) { + if (!members.has(name)) { + members.set(name, getUndefinedProperty(name)); + } + } } const stringIndexInfo = getIndexInfoOfType(type, IndexKind.String); const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number); @@ -10467,20 +10537,25 @@ namespace ts { numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly)); } - function getWidenedConstituentType(type: Type): Type { - return type.flags & TypeFlags.Nullable ? type : getWidenedType(type); + function getWidenedType(type: Type) { + return getWidenedTypeWithContext(type, /*context*/ undefined); } - function getWidenedType(type: Type): Type { + function getWidenedTypeWithContext(type: Type, context: WideningContext): Type { if (type.flags & TypeFlags.RequiresWidening) { if (type.flags & TypeFlags.Nullable) { return anyType; } - if (getObjectFlags(type) & ObjectFlags.ObjectLiteral) { - return getWidenedTypeOfObjectLiteral(type); + if (isObjectLiteralType(type)) { + return getWidenedTypeOfObjectLiteral(type, context); } if (type.flags & TypeFlags.Union) { - return getUnionType(sameMap((type).types, getWidenedConstituentType)); + const unionContext = context || createWideningContext(/*parent*/ undefined, /*propertyName*/ undefined, (type).types); + const widenedTypes = sameMap((type).types, t => t.flags & TypeFlags.Nullable ? t : getWidenedTypeWithContext(t, unionContext)); + // Widening an empty object literal transitions from a highly restrictive type to + // a highly inclusive one. For that reason we perform subtype reduction here if the + // union includes empty object types (e.g. reducing {} | string to just {}). + return getUnionType(widenedTypes, some(widenedTypes, isEmptyObjectType)); } if (isArrayType(type) || isTupleType(type)) { return createTypeReference((type).target, sameMap((type).typeArguments, getWidenedType)); @@ -10502,28 +10577,35 @@ namespace ts { */ function reportWideningErrorsInType(type: Type): boolean { let errorReported = false; - if (type.flags & TypeFlags.Union) { - for (const t of (type).types) { - if (reportWideningErrorsInType(t)) { + if (type.flags & TypeFlags.ContainsWideningType) { + if (type.flags & TypeFlags.Union) { + if (some((type).types, isEmptyObjectType)) { errorReported = true; } + else { + for (const t of (type).types) { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } + } + } } - } - if (isArrayType(type) || isTupleType(type)) { - for (const t of (type).typeArguments) { - if (reportWideningErrorsInType(t)) { - errorReported = true; + if (isArrayType(type) || isTupleType(type)) { + for (const t of (type).typeArguments) { + if (reportWideningErrorsInType(t)) { + errorReported = true; + } } } - } - if (getObjectFlags(type) & ObjectFlags.ObjectLiteral) { - for (const p of getPropertiesOfObjectType(type)) { - const t = getTypeOfSymbol(p); - if (t.flags & TypeFlags.ContainsWideningType) { - if (!reportWideningErrorsInType(t)) { - error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolName(p), typeToString(getWidenedType(t))); + if (isObjectLiteralType(type)) { + for (const p of getPropertiesOfObjectType(type)) { + const t = getTypeOfSymbol(p); + if (t.flags & TypeFlags.ContainsWideningType) { + if (!reportWideningErrorsInType(t)) { + error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, symbolName(p), typeToString(getWidenedType(t))); + } + errorReported = true; } - errorReported = true; } } } @@ -11029,11 +11111,28 @@ namespace ts { return constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index); } + function isObjectLiteralType(type: Type) { + return !!(getObjectFlags(type) & ObjectFlags.ObjectLiteral); + } + + function widenObjectLiteralCandidates(candidates: Type[]): Type[] { + if (candidates.length > 1) { + const objectLiterals = filter(candidates, isObjectLiteralType); + if (objectLiterals.length) { + const objectLiteralsType = getWidenedType(getUnionType(objectLiterals, /*subtypeReduction*/ true)); + return concatenate(filter(candidates, t => !isObjectLiteralType(t)), [objectLiteralsType]); + } + } + return candidates; + } + function getInferredType(context: InferenceContext, index: number): Type { const inference = context.inferences[index]; let inferredType = inference.inferredType; if (!inferredType) { if (inference.candidates) { + // Extract all object literal types and replace them with a single widened and normalized type. + const candidates = widenObjectLiteralCandidates(inference.candidates); // We widen inferred literal types if // all inferences were made to top-level ocurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and @@ -11042,7 +11141,7 @@ namespace ts { const widenLiteralTypes = inference.topLevel && !hasPrimitiveConstraint(inference.typeParameter) && (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); - const baseCandidates = widenLiteralTypes ? sameMap(inference.candidates, getWidenedLiteralType) : inference.candidates; + const baseCandidates = widenLiteralTypes ? sameMap(candidates, getWidenedLiteralType) : candidates; // If all inferences were made from contravariant positions, infer a common subtype. Otherwise, if // union types were requested or if all inferences were made from the return type position, infer a // union type. Otherwise, infer a common supertype. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ff2a33266ed54..e1830274c9308 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3327,6 +3327,7 @@ namespace ts { ObjectLiteral = 1 << 7, // Originates in an object literal EvolvingArray = 1 << 8, // Evolving array type ObjectLiteralPatternWithComputedProperties = 1 << 9, // Object literal pattern with computed properties + ContainsSpread = 1 << 10, // Object literal contains spread operation ClassOrInterface = Class | Interface } @@ -3609,6 +3610,14 @@ namespace ts { compareTypes: TypeComparer; // Type comparer function } + /* @internal */ + export interface WideningContext { + parent?: WideningContext; // Parent context + propertyName?: __String; // Name of property in parent + siblings?: Type[]; // Types of siblings + resolvedPropertyNames?: __String[]; // Property names occurring in sibling object literals + } + /* @internal */ export const enum SpecialPropertyAssignmentKind { None, diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 5d439e840b09f..26c03954b4544 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2040,6 +2040,7 @@ declare namespace ts { ObjectLiteral = 128, EvolvingArray = 256, ObjectLiteralPatternWithComputedProperties = 512, + ContainsSpread = 1024, ClassOrInterface = 3, } interface ObjectType extends Type { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2afef7d692cd9..6abf9d0cb6e16 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2040,6 +2040,7 @@ declare namespace ts { ObjectLiteral = 128, EvolvingArray = 256, ObjectLiteralPatternWithComputedProperties = 512, + ContainsSpread = 1024, ClassOrInterface = 3, } interface ObjectType extends Type { diff --git a/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt index 33cd913a2eb8b..12f9974484bbc 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration10_es2017.errors.txt @@ -4,11 +4,12 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,33): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,38): error TS1005: ';' expected. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,39): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,41): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,49): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts(1,53): error TS1109: Expression expected. -==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts (8 errors) ==== +==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration10_es2017.ts (9 errors) ==== async function foo(a = await => await): Promise { ~~~~~~~~~ !!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation. @@ -22,8 +23,11 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt index b974eacd88212..155119784ba9e 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration10_es5.errors.txt @@ -4,11 +4,12 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1 tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,33): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,38): error TS1005: ';' expected. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,39): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,41): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,49): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts(1,53): error TS1109: Expression expected. -==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts (8 errors) ==== +==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration10_es5.ts (9 errors) ==== async function foo(a = await => await): Promise { ~~~~~~~~~ !!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation. @@ -22,8 +23,11 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration1 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt index b752ec94a45a0..7f5266f931e30 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration10_es6.errors.txt @@ -4,11 +4,12 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration1 tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,33): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,38): error TS1005: ';' expected. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,39): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,41): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,49): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts(1,53): error TS1109: Expression expected. -==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts (8 errors) ==== +==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration10_es6.ts (9 errors) ==== async function foo(a = await => await): Promise { ~~~~~~~~~ !!! error TS2371: A parameter initializer is only allowed in a function or constructor implementation. @@ -22,8 +23,11 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration1 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt index 1fc74dfa0a20b..2d110f68127fc 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration5_es2017.errors.txt @@ -2,11 +2,12 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,20): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,25): error TS1005: ';' expected. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,26): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,28): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,36): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts(1,40): error TS1109: Expression expected. -==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts (6 errors) ==== +==== tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclaration5_es2017.ts (7 errors) ==== async function foo(await): Promise { ~~~~~ !!! error TS1138: Parameter declaration expected. @@ -16,8 +17,11 @@ tests/cases/conformance/async/es2017/functionDeclarations/asyncFunctionDeclarati !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt index 48299773218d2..6607ec7ff5c9f 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration5_es5.errors.txt @@ -2,11 +2,12 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5 tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,20): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,25): error TS1005: ';' expected. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,26): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,28): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,36): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts(1,40): error TS1109: Expression expected. -==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts (6 errors) ==== +==== tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5_es5.ts (7 errors) ==== async function foo(await): Promise { ~~~~~ !!! error TS1138: Parameter declaration expected. @@ -16,8 +17,11 @@ tests/cases/conformance/async/es5/functionDeclarations/asyncFunctionDeclaration5 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt b/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt index 2e907d1340016..ccddf6d5c044b 100644 --- a/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt +++ b/tests/baselines/reference/asyncFunctionDeclaration5_es6.errors.txt @@ -2,11 +2,12 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5 tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,20): error TS2304: Cannot find name 'await'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,25): error TS1005: ';' expected. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,26): error TS1128: Declaration or statement expected. +tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,28): error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,36): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts(1,40): error TS1109: Expression expected. -==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts (6 errors) ==== +==== tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5_es6.ts (7 errors) ==== async function foo(await): Promise { ~~~~~ !!! error TS1138: Parameter declaration expected. @@ -16,8 +17,11 @@ tests/cases/conformance/async/es6/functionDeclarations/asyncFunctionDeclaration5 !!! error TS1005: ';' expected. ~ !!! error TS1128: Declaration or statement expected. + ~~~~~~~~~~~~~~~ ~~~~ !!! error TS2532: Object is possibly 'undefined'. ~ !!! error TS1109: Expression expected. - } \ No newline at end of file + } + ~ +!!! error TS2365: Operator '>' cannot be applied to types 'boolean' and '{}'. \ No newline at end of file diff --git a/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types b/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types index f3ea48e637b53..9a10984a522de 100644 --- a/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types +++ b/tests/baselines/reference/bestCommonTypeOfConditionalExpressions.types @@ -47,7 +47,7 @@ var r = true ? 1 : 2; var r3 = true ? 1 : {}; >r3 : {} ->true ? 1 : {} : {} +>true ? 1 : {} : 1 | {} >true : true >1 : 1 >{} : {} diff --git a/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types b/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types index 3a655853163dc..a9767c72fc7cd 100644 --- a/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types +++ b/tests/baselines/reference/conditionalOperatorWithIdenticalBCT.types @@ -45,7 +45,7 @@ var result1 = true ? x : a; //Expr1 and Expr2 are literals true ? {} : 1; ->true ? {} : 1 : {} +>true ? {} : 1 : 1 | {} >true : true >{} : {} >1 : 1 @@ -64,13 +64,13 @@ true ? { a: 1 } : { a: 2, b: 'string' }; var result2 = true ? {} : 1; >result2 : {} ->true ? {} : 1 : {} +>true ? {} : 1 : 1 | {} >true : true >{} : {} >1 : 1 var result3 = true ? { a: 1 } : { a: 2, b: 'string' }; ->result3 : { a: number; } | { a: number; b: string; } +>result3 : { a: number; b?: undefined; } | { a: number; b: string; } >true ? { a: 1 } : { a: 2, b: 'string' } : { a: number; } | { a: number; b: string; } >true : true >{ a: 1 } : { a: number; } @@ -125,7 +125,7 @@ var result5 = true ? a : x; //Expr1 and Expr2 are literals true ? 1 : {}; ->true ? 1 : {} : {} +>true ? 1 : {} : 1 | {} >true : true >1 : 1 >{} : {} @@ -144,13 +144,13 @@ true ? { a: 2, b: 'string' } : { a: 1 }; var result6 = true ? 1 : {}; >result6 : {} ->true ? 1 : {} : {} +>true ? 1 : {} : 1 | {} >true : true >1 : 1 >{} : {} var result7 = true ? { a: 2, b: 'string' } : { a: 1 }; ->result7 : { a: number; b: string; } | { a: number; } +>result7 : { a: number; b: string; } | { a: number; b?: undefined; } >true ? { a: 2, b: 'string' } : { a: 1 } : { a: number; b: string; } | { a: number; } >true : true >{ a: 2, b: 'string' } : { a: number; b: string; } diff --git a/tests/baselines/reference/heterogeneousArrayLiterals.types b/tests/baselines/reference/heterogeneousArrayLiterals.types index f1c5b6b8dfc27..2655f7c2d71b8 100644 --- a/tests/baselines/reference/heterogeneousArrayLiterals.types +++ b/tests/baselines/reference/heterogeneousArrayLiterals.types @@ -22,13 +22,13 @@ var c = [1, '', null]; // {}[] var d = [{}, 1]; // {}[] >d : {}[] ->[{}, 1] : {}[] +>[{}, 1] : (number | {})[] >{} : {} >1 : 1 var e = [{}, Object]; // {}[] >e : {}[] ->[{}, Object] : {}[] +>[{}, Object] : (ObjectConstructor | {})[] >{} : {} >Object : ObjectConstructor @@ -48,7 +48,7 @@ var g = [[1], ['']]; // {}[] >'' : "" var h = [{ foo: 1, bar: '' }, { foo: 2 }]; // {foo: number}[] ->h : ({ foo: number; bar: string; } | { foo: number; })[] +>h : ({ foo: number; bar: string; } | { foo: number; bar?: undefined; })[] >[{ foo: 1, bar: '' }, { foo: 2 }] : ({ foo: number; bar: string; } | { foo: number; })[] >{ foo: 1, bar: '' } : { foo: number; bar: string; } >foo : number @@ -60,7 +60,7 @@ var h = [{ foo: 1, bar: '' }, { foo: 2 }]; // {foo: number}[] >2 : 2 var i = [{ foo: 1, bar: '' }, { foo: '' }]; // {}[] ->i : ({ foo: number; bar: string; } | { foo: string; })[] +>i : ({ foo: number; bar: string; } | { foo: string; bar?: undefined; })[] >[{ foo: 1, bar: '' }, { foo: '' }] : ({ foo: number; bar: string; } | { foo: string; })[] >{ foo: 1, bar: '' } : { foo: number; bar: string; } >foo : number @@ -145,7 +145,7 @@ module Derived { >Derived : typeof Derived var h = [{ foo: base, basear: derived }, { foo: base }]; // {foo: Base}[] ->h : ({ foo: Base; basear: Derived; } | { foo: Base; })[] +>h : ({ foo: Base; basear: Derived; } | { foo: Base; basear?: undefined; })[] >[{ foo: base, basear: derived }, { foo: base }] : ({ foo: Base; basear: Derived; } | { foo: Base; })[] >{ foo: base, basear: derived } : { foo: Base; basear: Derived; } >foo : Base @@ -157,7 +157,7 @@ module Derived { >base : Base var i = [{ foo: base, basear: derived }, { foo: derived }]; // {foo: Derived}[] ->i : ({ foo: Base; basear: Derived; } | { foo: Derived; })[] +>i : ({ foo: Base; basear: Derived; } | { foo: Derived; basear?: undefined; })[] >[{ foo: base, basear: derived }, { foo: derived }] : ({ foo: Base; basear: Derived; } | { foo: Derived; })[] >{ foo: base, basear: derived } : { foo: Base; basear: Derived; } >foo : Base diff --git a/tests/baselines/reference/incompatibleTypes.types b/tests/baselines/reference/incompatibleTypes.types index 053bf6bf099c3..d88a09a4b7223 100644 --- a/tests/baselines/reference/incompatibleTypes.types +++ b/tests/baselines/reference/incompatibleTypes.types @@ -176,7 +176,7 @@ var o1: { a: { a: string; }; b: string; } = { e: 0, f: 0 }; >0 : 0 var a1 = [{ e: 0, f: 0 }, { e: 0, f: 0 }, { e: 0, g: 0 }]; ->a1 : ({ e: number; f: number; } | { e: number; g: number; })[] +>a1 : ({ e: number; f: number; g?: undefined; } | { e: number; g: number; f?: undefined; })[] >[{ e: 0, f: 0 }, { e: 0, f: 0 }, { e: 0, g: 0 }] : ({ e: number; f: number; } | { e: number; g: number; })[] >{ e: 0, f: 0 } : { e: number; f: number; } >e : number diff --git a/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types b/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types index ecd3fc5270900..bc7bcbf4c2e16 100644 --- a/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types +++ b/tests/baselines/reference/logicalOrOperatorWithTypeParameters.types @@ -107,8 +107,8 @@ function fn3u : U var r3 = t || { a: '' }; ->r3 : { a: string; } ->t || { a: '' } : { a: string; } +>r3 : T | { a: string; } +>t || { a: '' } : T | { a: string; } >t : T >{ a: '' } : { a: string; } >a : string diff --git a/tests/baselines/reference/objectLiteralNormalization.errors.txt b/tests/baselines/reference/objectLiteralNormalization.errors.txt new file mode 100644 index 0000000000000..6bdc9b955e324 --- /dev/null +++ b/tests/baselines/reference/objectLiteralNormalization.errors.txt @@ -0,0 +1,92 @@ +tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(7,1): error TS2322: Type '{ a: number; b: number; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. + Type '{ a: number; b: number; }' is not assignable to type '{ a: number; b: string; c: boolean; }'. + Property 'c' is missing in type '{ a: number; b: number; }'. +tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(8,1): error TS2322: Type '{ b: string; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. + Type '{ b: string; }' is not assignable to type '{ a: number; b: string; c: boolean; }'. + Property 'a' is missing in type '{ b: string; }'. +tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(9,1): error TS2322: Type '{ c: true; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. + Type '{ c: true; }' is not assignable to type '{ a: number; b: string; c: boolean; }'. + Property 'a' is missing in type '{ c: true; }'. +tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(17,1): error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'. + Type '{ a: string; b: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'. + Types of property 'a' are incompatible. + Type 'string' is not assignable to type 'undefined'. +tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts(18,1): error TS2322: Type '{ a: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'. + Type '{ a: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'. + Types of property 'a' are incompatible. + Type 'number' is not assignable to type 'undefined'. + + +==== tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts (5 errors) ==== + // Object literals in unions are normalized upon widening + let a1 = [{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }][0]; + a1.a; // number + a1.b; // string | undefined + a1.c; // boolean | undefined + a1 = { a: 1 }; + a1 = { a: 0, b: 0 }; // Error + ~~ +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. +!!! error TS2322: Type '{ a: number; b: number; }' is not assignable to type '{ a: number; b: string; c: boolean; }'. +!!! error TS2322: Property 'c' is missing in type '{ a: number; b: number; }'. + a1 = { b: "y" }; // Error + ~~ +!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. +!!! error TS2322: Type '{ b: string; }' is not assignable to type '{ a: number; b: string; c: boolean; }'. +!!! error TS2322: Property 'a' is missing in type '{ b: string; }'. + a1 = { c: true }; // Error + ~~ +!!! error TS2322: Type '{ c: true; }' is not assignable to type '{ a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; }'. +!!! error TS2322: Type '{ c: true; }' is not assignable to type '{ a: number; b: string; c: boolean; }'. +!!! error TS2322: Property 'a' is missing in type '{ c: true; }'. + + let a2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0]; + a2.a; // string | number | undefined + a2.b; // number | undefined + a2 = { a: 10, b: 20 }; + a2 = { a: "def" }; + a2 = {}; + a2 = { a: "def", b: 20 }; // Error + ~~ +!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'. +!!! error TS2322: Type '{ a: string; b: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'undefined'. + a2 = { a: 1 }; // Error + ~~ +!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; }'. +!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ a?: undefined; b?: undefined; }'. +!!! error TS2322: Types of property 'a' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'undefined'. + + // Object literals containing spreads are not normalized + declare let b1: { a: string, b: string } | { b: string, c: string }; + let b2 = { ...b1, z: 55 }; + let b3 = { ...b2 }; + + // Before widening {} acts like { [x: string]: undefined }, which is a + // subtype of types with all optional properties + declare let opts: { foo?: string, bar?: string, baz?: boolean }; + let c1 = !true ? {} : opts; + let c2 = !true ? opts : {}; + let c3 = !true ? { a: 0, b: 0 } : {}; + let c4 = !true ? {} : { a: 0, b: 0 }; + + // Normalization applies to nested properties + let d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0]; + d1.kind; + d1.pos; + d1.pos.x; + d1.pos.y; + d1.pos.a; + d1.pos.b; + + declare function f(...items: T[]): T; + declare let data: { a: 1, b: "abc", c: true }; + + // Object literals are inferred as a single normalized union type + let e1 = f({ a: 1, b: 2 }, { a: "abc" }, {}); + let e2 = f({}, { a: "abc" }, { a: 1, b: 2 }); + let e3 = f(data, { a: 2 }); + let e4 = f({ a: 2 }, data); + \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralNormalization.js b/tests/baselines/reference/objectLiteralNormalization.js new file mode 100644 index 0000000000000..153ed72b5b39a --- /dev/null +++ b/tests/baselines/reference/objectLiteralNormalization.js @@ -0,0 +1,232 @@ +//// [objectLiteralNormalization.ts] +// Object literals in unions are normalized upon widening +let a1 = [{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }][0]; +a1.a; // number +a1.b; // string | undefined +a1.c; // boolean | undefined +a1 = { a: 1 }; +a1 = { a: 0, b: 0 }; // Error +a1 = { b: "y" }; // Error +a1 = { c: true }; // Error + +let a2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0]; +a2.a; // string | number | undefined +a2.b; // number | undefined +a2 = { a: 10, b: 20 }; +a2 = { a: "def" }; +a2 = {}; +a2 = { a: "def", b: 20 }; // Error +a2 = { a: 1 }; // Error + +// Object literals containing spreads are not normalized +declare let b1: { a: string, b: string } | { b: string, c: string }; +let b2 = { ...b1, z: 55 }; +let b3 = { ...b2 }; + +// Before widening {} acts like { [x: string]: undefined }, which is a +// subtype of types with all optional properties +declare let opts: { foo?: string, bar?: string, baz?: boolean }; +let c1 = !true ? {} : opts; +let c2 = !true ? opts : {}; +let c3 = !true ? { a: 0, b: 0 } : {}; +let c4 = !true ? {} : { a: 0, b: 0 }; + +// Normalization applies to nested properties +let d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0]; +d1.kind; +d1.pos; +d1.pos.x; +d1.pos.y; +d1.pos.a; +d1.pos.b; + +declare function f(...items: T[]): T; +declare let data: { a: 1, b: "abc", c: true }; + +// Object literals are inferred as a single normalized union type +let e1 = f({ a: 1, b: 2 }, { a: "abc" }, {}); +let e2 = f({}, { a: "abc" }, { a: 1, b: 2 }); +let e3 = f(data, { a: 2 }); +let e4 = f({ a: 2 }, data); + + +//// [objectLiteralNormalization.js] +"use strict"; +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +// Object literals in unions are normalized upon widening +var a1 = [{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }][0]; +a1.a; // number +a1.b; // string | undefined +a1.c; // boolean | undefined +a1 = { a: 1 }; +a1 = { a: 0, b: 0 }; // Error +a1 = { b: "y" }; // Error +a1 = { c: true }; // Error +var a2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0]; +a2.a; // string | number | undefined +a2.b; // number | undefined +a2 = { a: 10, b: 20 }; +a2 = { a: "def" }; +a2 = {}; +a2 = { a: "def", b: 20 }; // Error +a2 = { a: 1 }; // Error +var b2 = __assign({}, b1, { z: 55 }); +var b3 = __assign({}, b2); +var c1 = !true ? {} : opts; +var c2 = !true ? opts : {}; +var c3 = !true ? { a: 0, b: 0 } : {}; +var c4 = !true ? {} : { a: 0, b: 0 }; +// Normalization applies to nested properties +var d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0]; +d1.kind; +d1.pos; +d1.pos.x; +d1.pos.y; +d1.pos.a; +d1.pos.b; +// Object literals are inferred as a single normalized union type +var e1 = f({ a: 1, b: 2 }, { a: "abc" }, {}); +var e2 = f({}, { a: "abc" }, { a: 1, b: 2 }); +var e3 = f(data, { a: 2 }); +var e4 = f({ a: 2 }, data); + + +//// [objectLiteralNormalization.d.ts] +declare let a1: { + a: number; + b?: undefined; + c?: undefined; +} | { + a: number; + b: string; + c?: undefined; +} | { + a: number; + b: string; + c: boolean; +}; +declare let a2: { + a: number; + b: number; +} | { + a: string; + b?: undefined; +} | { + a?: undefined; + b?: undefined; +}; +declare let b1: { + a: string; + b: string; +} | { + b: string; + c: string; +}; +declare let b2: { + z: number; + a: string; + b: string; +} | { + z: number; + b: string; + c: string; +}; +declare let b3: { + z: number; + a: string; + b: string; +} | { + z: number; + b: string; + c: string; +}; +declare let opts: { + foo?: string; + bar?: string; + baz?: boolean; +}; +declare let c1: { + foo?: string | undefined; + bar?: string | undefined; + baz?: boolean | undefined; +}; +declare let c2: { + foo?: string | undefined; + bar?: string | undefined; + baz?: boolean | undefined; +}; +declare let c3: { + a: number; + b: number; +} | { + a?: undefined; + b?: undefined; +}; +declare let c4: { + a?: undefined; + b?: undefined; +} | { + a: number; + b: number; +}; +declare let d1: { + kind: string; + pos: { + x: number; + y: number; + a?: undefined; + b?: undefined; + }; +} | { + kind: string; + pos: { + a: string; + x?: undefined; + y?: undefined; + b?: undefined; + } | { + b: number; + x?: undefined; + y?: undefined; + a?: undefined; + }; +}; +declare function f(...items: T[]): T; +declare let data: { + a: 1; + b: "abc"; + c: true; +}; +declare let e1: { + a: number; + b: number; +} | { + a: string; + b?: undefined; +} | { + a?: undefined; + b?: undefined; +}; +declare let e2: { + a?: undefined; + b?: undefined; +} | { + a: string; + b?: undefined; +} | { + a: number; + b: number; +}; +declare let e3: { + a: number; +}; +declare let e4: { + a: number; +}; diff --git a/tests/baselines/reference/objectLiteralNormalization.symbols b/tests/baselines/reference/objectLiteralNormalization.symbols new file mode 100644 index 0000000000000..69882d81f76c1 --- /dev/null +++ b/tests/baselines/reference/objectLiteralNormalization.symbols @@ -0,0 +1,213 @@ +=== tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts === +// Object literals in unions are normalized upon widening +let a1 = [{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }][0]; +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 1, 11)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 1, 21)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 27)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 1, 39)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 45)) +>c : Symbol(c, Decl(objectLiteralNormalization.ts, 1, 53)) + +a1.a; // number +>a1.a : Symbol(a, Decl(objectLiteralNormalization.ts, 1, 11), Decl(objectLiteralNormalization.ts, 1, 21), Decl(objectLiteralNormalization.ts, 1, 39)) +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 1, 11), Decl(objectLiteralNormalization.ts, 1, 21), Decl(objectLiteralNormalization.ts, 1, 39)) + +a1.b; // string | undefined +>a1.b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 27), Decl(objectLiteralNormalization.ts, 1, 45)) +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 1, 27), Decl(objectLiteralNormalization.ts, 1, 45)) + +a1.c; // boolean | undefined +>a1.c : Symbol(c, Decl(objectLiteralNormalization.ts, 1, 53)) +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>c : Symbol(c, Decl(objectLiteralNormalization.ts, 1, 53)) + +a1 = { a: 1 }; +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 5, 6)) + +a1 = { a: 0, b: 0 }; // Error +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 6, 6)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 6, 12)) + +a1 = { b: "y" }; // Error +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 7, 6)) + +a1 = { c: true }; // Error +>a1 : Symbol(a1, Decl(objectLiteralNormalization.ts, 1, 3)) +>c : Symbol(c, Decl(objectLiteralNormalization.ts, 8, 6)) + +let a2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0]; +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 27)) + +a2.a; // string | number | undefined +>a2.a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11), Decl(objectLiteralNormalization.ts, 10, 27)) +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 10, 11), Decl(objectLiteralNormalization.ts, 10, 27)) + +a2.b; // number | undefined +>a2.b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17)) +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 10, 17)) + +a2 = { a: 10, b: 20 }; +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 13, 6)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 13, 13)) + +a2 = { a: "def" }; +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 14, 6)) + +a2 = {}; +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) + +a2 = { a: "def", b: 20 }; // Error +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 16, 6)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 16, 16)) + +a2 = { a: 1 }; // Error +>a2 : Symbol(a2, Decl(objectLiteralNormalization.ts, 10, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 17, 6)) + +// Object literals containing spreads are not normalized +declare let b1: { a: string, b: string } | { b: string, c: string }; +>b1 : Symbol(b1, Decl(objectLiteralNormalization.ts, 20, 11)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 20, 17)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 20, 28)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 20, 44)) +>c : Symbol(c, Decl(objectLiteralNormalization.ts, 20, 55)) + +let b2 = { ...b1, z: 55 }; +>b2 : Symbol(b2, Decl(objectLiteralNormalization.ts, 21, 3)) +>b1 : Symbol(b1, Decl(objectLiteralNormalization.ts, 20, 11)) +>z : Symbol(z, Decl(objectLiteralNormalization.ts, 21, 17)) + +let b3 = { ...b2 }; +>b3 : Symbol(b3, Decl(objectLiteralNormalization.ts, 22, 3)) +>b2 : Symbol(b2, Decl(objectLiteralNormalization.ts, 21, 3)) + +// Before widening {} acts like { [x: string]: undefined }, which is a +// subtype of types with all optional properties +declare let opts: { foo?: string, bar?: string, baz?: boolean }; +>opts : Symbol(opts, Decl(objectLiteralNormalization.ts, 26, 11)) +>foo : Symbol(foo, Decl(objectLiteralNormalization.ts, 26, 19)) +>bar : Symbol(bar, Decl(objectLiteralNormalization.ts, 26, 33)) +>baz : Symbol(baz, Decl(objectLiteralNormalization.ts, 26, 47)) + +let c1 = !true ? {} : opts; +>c1 : Symbol(c1, Decl(objectLiteralNormalization.ts, 27, 3)) +>opts : Symbol(opts, Decl(objectLiteralNormalization.ts, 26, 11)) + +let c2 = !true ? opts : {}; +>c2 : Symbol(c2, Decl(objectLiteralNormalization.ts, 28, 3)) +>opts : Symbol(opts, Decl(objectLiteralNormalization.ts, 26, 11)) + +let c3 = !true ? { a: 0, b: 0 } : {}; +>c3 : Symbol(c3, Decl(objectLiteralNormalization.ts, 29, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 29, 18)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 29, 24)) + +let c4 = !true ? {} : { a: 0, b: 0 }; +>c4 : Symbol(c4, Decl(objectLiteralNormalization.ts, 30, 3)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 30, 23)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 30, 29)) + +// Normalization applies to nested properties +let d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0]; +>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3)) +>kind : Symbol(kind, Decl(objectLiteralNormalization.ts, 33, 11)) +>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22)) +>x : Symbol(x, Decl(objectLiteralNormalization.ts, 33, 29)) +>y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35)) +>kind : Symbol(kind, Decl(objectLiteralNormalization.ts, 33, 47)) +>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 58)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 33, 73)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 33, 86)) + +d1.kind; +>d1.kind : Symbol(kind, Decl(objectLiteralNormalization.ts, 33, 11), Decl(objectLiteralNormalization.ts, 33, 47)) +>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3)) +>kind : Symbol(kind, Decl(objectLiteralNormalization.ts, 33, 11), Decl(objectLiteralNormalization.ts, 33, 47)) + +d1.pos; +>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3)) +>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) + +d1.pos.x; +>d1.pos.x : Symbol(x, Decl(objectLiteralNormalization.ts, 33, 29)) +>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3)) +>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>x : Symbol(x, Decl(objectLiteralNormalization.ts, 33, 29)) + +d1.pos.y; +>d1.pos.y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35)) +>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3)) +>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>y : Symbol(y, Decl(objectLiteralNormalization.ts, 33, 35)) + +d1.pos.a; +>d1.pos.a : Symbol(a, Decl(objectLiteralNormalization.ts, 33, 73)) +>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3)) +>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 33, 73)) + +d1.pos.b; +>d1.pos.b : Symbol(b, Decl(objectLiteralNormalization.ts, 33, 86)) +>d1.pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>d1 : Symbol(d1, Decl(objectLiteralNormalization.ts, 33, 3)) +>pos : Symbol(pos, Decl(objectLiteralNormalization.ts, 33, 22), Decl(objectLiteralNormalization.ts, 33, 58)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 33, 86)) + +declare function f(...items: T[]): T; +>f : Symbol(f, Decl(objectLiteralNormalization.ts, 39, 9)) +>T : Symbol(T, Decl(objectLiteralNormalization.ts, 41, 19)) +>items : Symbol(items, Decl(objectLiteralNormalization.ts, 41, 22)) +>T : Symbol(T, Decl(objectLiteralNormalization.ts, 41, 19)) +>T : Symbol(T, Decl(objectLiteralNormalization.ts, 41, 19)) + +declare let data: { a: 1, b: "abc", c: true }; +>data : Symbol(data, Decl(objectLiteralNormalization.ts, 42, 11)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 42, 19)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 42, 25)) +>c : Symbol(c, Decl(objectLiteralNormalization.ts, 42, 35)) + +// Object literals are inferred as a single normalized union type +let e1 = f({ a: 1, b: 2 }, { a: "abc" }, {}); +>e1 : Symbol(e1, Decl(objectLiteralNormalization.ts, 45, 3)) +>f : Symbol(f, Decl(objectLiteralNormalization.ts, 39, 9)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 45, 12)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 45, 18)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 45, 28)) + +let e2 = f({}, { a: "abc" }, { a: 1, b: 2 }); +>e2 : Symbol(e2, Decl(objectLiteralNormalization.ts, 46, 3)) +>f : Symbol(f, Decl(objectLiteralNormalization.ts, 39, 9)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 46, 16)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 46, 30)) +>b : Symbol(b, Decl(objectLiteralNormalization.ts, 46, 36)) + +let e3 = f(data, { a: 2 }); +>e3 : Symbol(e3, Decl(objectLiteralNormalization.ts, 47, 3)) +>f : Symbol(f, Decl(objectLiteralNormalization.ts, 39, 9)) +>data : Symbol(data, Decl(objectLiteralNormalization.ts, 42, 11)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 47, 18)) + +let e4 = f({ a: 2 }, data); +>e4 : Symbol(e4, Decl(objectLiteralNormalization.ts, 48, 3)) +>f : Symbol(f, Decl(objectLiteralNormalization.ts, 39, 9)) +>a : Symbol(a, Decl(objectLiteralNormalization.ts, 48, 12)) +>data : Symbol(data, Decl(objectLiteralNormalization.ts, 42, 11)) + diff --git a/tests/baselines/reference/objectLiteralNormalization.types b/tests/baselines/reference/objectLiteralNormalization.types new file mode 100644 index 0000000000000..8fa49c9d9acbe --- /dev/null +++ b/tests/baselines/reference/objectLiteralNormalization.types @@ -0,0 +1,326 @@ +=== tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts === +// Object literals in unions are normalized upon widening +let a1 = [{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }][0]; +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>[{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }][0] : { a: number; } | { a: number; b: string; } | { a: number; b: string; c: boolean; } +>[{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }] : ({ a: number; } | { a: number; b: string; } | { a: number; b: string; c: boolean; })[] +>{ a: 0 } : { a: number; } +>a : number +>0 : 0 +>{ a: 1, b: "x" } : { a: number; b: string; } +>a : number +>1 : 1 +>b : string +>"x" : "x" +>{ a: 2, b: "y", c: true } : { a: number; b: string; c: boolean; } +>a : number +>2 : 2 +>b : string +>"y" : "y" +>c : boolean +>true : true +>0 : 0 + +a1.a; // number +>a1.a : number +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>a : number + +a1.b; // string | undefined +>a1.b : string | undefined +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>b : string | undefined + +a1.c; // boolean | undefined +>a1.c : boolean | undefined +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>c : boolean | undefined + +a1 = { a: 1 }; +>a1 = { a: 1 } : { a: number; } +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 + +a1 = { a: 0, b: 0 }; // Error +>a1 = { a: 0, b: 0 } : { a: number; b: number; } +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>{ a: 0, b: 0 } : { a: number; b: number; } +>a : number +>0 : 0 +>b : number +>0 : 0 + +a1 = { b: "y" }; // Error +>a1 = { b: "y" } : { b: string; } +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>{ b: "y" } : { b: string; } +>b : string +>"y" : "y" + +a1 = { c: true }; // Error +>a1 = { c: true } : { c: true; } +>a1 : { a: number; b?: undefined; c?: undefined; } | { a: number; b: string; c?: undefined; } | { a: number; b: string; c: boolean; } +>{ c: true } : { c: true; } +>c : boolean +>true : true + +let a2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0]; +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>[{ a: 1, b: 2 }, { a: "abc" }, {}][0] : { a: number; b: number; } | { a: string; } | {} +>[{ a: 1, b: 2 }, { a: "abc" }, {}] : ({ a: number; b: number; } | { a: string; } | {})[] +>{ a: 1, b: 2 } : { a: number; b: number; } +>a : number +>1 : 1 +>b : number +>2 : 2 +>{ a: "abc" } : { a: string; } +>a : string +>"abc" : "abc" +>{} : {} +>0 : 0 + +a2.a; // string | number | undefined +>a2.a : string | number | undefined +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>a : string | number | undefined + +a2.b; // number | undefined +>a2.b : number | undefined +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>b : number | undefined + +a2 = { a: 10, b: 20 }; +>a2 = { a: 10, b: 20 } : { a: number; b: number; } +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>{ a: 10, b: 20 } : { a: number; b: number; } +>a : number +>10 : 10 +>b : number +>20 : 20 + +a2 = { a: "def" }; +>a2 = { a: "def" } : { a: string; } +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>{ a: "def" } : { a: string; } +>a : string +>"def" : "def" + +a2 = {}; +>a2 = {} : {} +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>{} : {} + +a2 = { a: "def", b: 20 }; // Error +>a2 = { a: "def", b: 20 } : { a: string; b: number; } +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>{ a: "def", b: 20 } : { a: string; b: number; } +>a : string +>"def" : "def" +>b : number +>20 : 20 + +a2 = { a: 1 }; // Error +>a2 = { a: 1 } : { a: number; } +>a2 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>{ a: 1 } : { a: number; } +>a : number +>1 : 1 + +// Object literals containing spreads are not normalized +declare let b1: { a: string, b: string } | { b: string, c: string }; +>b1 : { a: string; b: string; } | { b: string; c: string; } +>a : string +>b : string +>b : string +>c : string + +let b2 = { ...b1, z: 55 }; +>b2 : { z: number; a: string; b: string; } | { z: number; b: string; c: string; } +>{ ...b1, z: 55 } : { z: number; a: string; b: string; } | { z: number; b: string; c: string; } +>b1 : { a: string; b: string; } | { b: string; c: string; } +>z : number +>55 : 55 + +let b3 = { ...b2 }; +>b3 : { z: number; a: string; b: string; } | { z: number; b: string; c: string; } +>{ ...b2 } : { z: number; a: string; b: string; } | { z: number; b: string; c: string; } +>b2 : { z: number; a: string; b: string; } | { z: number; b: string; c: string; } + +// Before widening {} acts like { [x: string]: undefined }, which is a +// subtype of types with all optional properties +declare let opts: { foo?: string, bar?: string, baz?: boolean }; +>opts : { foo?: string | undefined; bar?: string | undefined; baz?: boolean | undefined; } +>foo : string | undefined +>bar : string | undefined +>baz : boolean | undefined + +let c1 = !true ? {} : opts; +>c1 : { foo?: string | undefined; bar?: string | undefined; baz?: boolean | undefined; } +>!true ? {} : opts : { foo?: string | undefined; bar?: string | undefined; baz?: boolean | undefined; } +>!true : false +>true : true +>{} : {} +>opts : { foo?: string | undefined; bar?: string | undefined; baz?: boolean | undefined; } + +let c2 = !true ? opts : {}; +>c2 : { foo?: string | undefined; bar?: string | undefined; baz?: boolean | undefined; } +>!true ? opts : {} : { foo?: string | undefined; bar?: string | undefined; baz?: boolean | undefined; } +>!true : false +>true : true +>opts : { foo?: string | undefined; bar?: string | undefined; baz?: boolean | undefined; } +>{} : {} + +let c3 = !true ? { a: 0, b: 0 } : {}; +>c3 : { a: number; b: number; } | { a?: undefined; b?: undefined; } +>!true ? { a: 0, b: 0 } : {} : { a: number; b: number; } | {} +>!true : false +>true : true +>{ a: 0, b: 0 } : { a: number; b: number; } +>a : number +>0 : 0 +>b : number +>0 : 0 +>{} : {} + +let c4 = !true ? {} : { a: 0, b: 0 }; +>c4 : { a?: undefined; b?: undefined; } | { a: number; b: number; } +>!true ? {} : { a: 0, b: 0 } : {} | { a: number; b: number; } +>!true : false +>true : true +>{} : {} +>{ a: 0, b: 0 } : { a: number; b: number; } +>a : number +>0 : 0 +>b : number +>0 : 0 + +// Normalization applies to nested properties +let d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0]; +>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; }; } +>[{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0] : { kind: string; pos: { x: number; y: number; }; } | { kind: string; pos: { a: string; } | { b: number; }; } +>[{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }] : ({ kind: string; pos: { x: number; y: number; }; } | { kind: string; pos: { a: string; } | { b: number; }; })[] +>{ kind: 'a', pos: { x: 0, y: 0 } } : { kind: string; pos: { x: number; y: number; }; } +>kind : string +>'a' : "a" +>pos : { x: number; y: number; } +>{ x: 0, y: 0 } : { x: number; y: number; } +>x : number +>0 : 0 +>y : number +>0 : 0 +>{ kind: 'b', pos: !true ? { a: "x" } : { b: 0 } } : { kind: string; pos: { a: string; } | { b: number; }; } +>kind : string +>'b' : "b" +>pos : { a: string; } | { b: number; } +>!true ? { a: "x" } : { b: 0 } : { a: string; } | { b: number; } +>!true : false +>true : true +>{ a: "x" } : { a: string; } +>a : string +>"x" : "x" +>{ b: 0 } : { b: number; } +>b : number +>0 : 0 +>0 : 0 + +d1.kind; +>d1.kind : string +>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; }; } +>kind : string + +d1.pos; +>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; }; } +>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } + +d1.pos.x; +>d1.pos.x : number | undefined +>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; }; } +>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>x : number | undefined + +d1.pos.y; +>d1.pos.y : number | undefined +>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; }; } +>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>y : number | undefined + +d1.pos.a; +>d1.pos.a : string | undefined +>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; }; } +>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>a : string | undefined + +d1.pos.b; +>d1.pos.b : number | undefined +>d1.pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>d1 : { kind: string; pos: { x: number; y: number; a?: undefined; b?: undefined; }; } | { kind: string; pos: { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; }; } +>pos : { x: number; y: number; a?: undefined; b?: undefined; } | { a: string; x?: undefined; y?: undefined; b?: undefined; } | { b: number; x?: undefined; y?: undefined; a?: undefined; } +>b : number | undefined + +declare function f(...items: T[]): T; +>f : (...items: T[]) => T +>T : T +>items : T[] +>T : T +>T : T + +declare let data: { a: 1, b: "abc", c: true }; +>data : { a: 1; b: "abc"; c: true; } +>a : 1 +>b : "abc" +>c : true +>true : true + +// Object literals are inferred as a single normalized union type +let e1 = f({ a: 1, b: 2 }, { a: "abc" }, {}); +>e1 : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>f({ a: 1, b: 2 }, { a: "abc" }, {}) : { a: number; b: number; } | { a: string; b?: undefined; } | { a?: undefined; b?: undefined; } +>f : (...items: T[]) => T +>{ a: 1, b: 2 } : { a: number; b: number; } +>a : number +>1 : 1 +>b : number +>2 : 2 +>{ a: "abc" } : { a: string; } +>a : string +>"abc" : "abc" +>{} : {} + +let e2 = f({}, { a: "abc" }, { a: 1, b: 2 }); +>e2 : { a?: undefined; b?: undefined; } | { a: string; b?: undefined; } | { a: number; b: number; } +>f({}, { a: "abc" }, { a: 1, b: 2 }) : { a?: undefined; b?: undefined; } | { a: string; b?: undefined; } | { a: number; b: number; } +>f : (...items: T[]) => T +>{} : {} +>{ a: "abc" } : { a: string; } +>a : string +>"abc" : "abc" +>{ a: 1, b: 2 } : { a: number; b: number; } +>a : number +>1 : 1 +>b : number +>2 : 2 + +let e3 = f(data, { a: 2 }); +>e3 : { a: number; } +>f(data, { a: 2 }) : { a: number; } +>f : (...items: T[]) => T +>data : { a: 1; b: "abc"; c: true; } +>{ a: 2 } : { a: number; } +>a : number +>2 : 2 + +let e4 = f({ a: 2 }, data); +>e4 : { a: number; } +>f({ a: 2 }, data) : { a: number; } +>f : (...items: T[]) => T +>{ a: 2 } : { a: number; } +>a : number +>2 : 2 +>data : { a: 1; b: "abc"; c: true; } + diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 0caef49f4399e..5166ceb54d7cf 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -295,7 +295,7 @@ function conditionalSpreadBoolean(b: boolean) : { x: number, y: number } { >14 : 14 } let o2 = { ...b && { x: 21 }} ->o2 : {} | { x: number; } +>o2 : {} >{ ...b && { x: 21 }} : {} | { x: number; } >b && { x: 21 } : false | { x: number; } >b : boolean @@ -336,7 +336,7 @@ function conditionalSpreadNumber(nt: number): { x: number, y: number } { >nt : number } let o2 = { ...nt && { x: nt }} ->o2 : {} | { x: number; } +>o2 : {} >{ ...nt && { x: nt }} : {} | { x: number; } >nt && { x: nt } : 0 | { x: number; } >nt : number @@ -377,7 +377,7 @@ function conditionalSpreadString(st: string): { x: string, y: number } { >st : string } let o2 = { ...st && { x: st }} ->o2 : {} | { x: string; } +>o2 : {} >{ ...st && { x: st }} : {} | { x: string; } >st && { x: st } : "" | { x: string; } >st : string diff --git a/tests/baselines/reference/primitiveMembers.types b/tests/baselines/reference/primitiveMembers.types index 70ca0eb34e73d..cb2a6245dd0cc 100644 --- a/tests/baselines/reference/primitiveMembers.types +++ b/tests/baselines/reference/primitiveMembers.types @@ -78,7 +78,7 @@ var b: Boolean = true; var n3 = 5 || {}; >n3 : {} ->5 || {} : {} +>5 || {} : 5 | {} >5 : 5 >{} : {} diff --git a/tests/baselines/reference/spreadUnion2.errors.txt b/tests/baselines/reference/spreadUnion2.errors.txt new file mode 100644 index 0000000000000..f4f81dadf1108 --- /dev/null +++ b/tests/baselines/reference/spreadUnion2.errors.txt @@ -0,0 +1,41 @@ +tests/cases/conformance/types/spread/spreadUnion2.ts(5,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o1' has type '{} | { a: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 3:4, but here has type '{}'. +tests/cases/conformance/types/spread/spreadUnion2.ts(8,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o2' has type '{} | { b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 6:4, but here has type '{}'. +tests/cases/conformance/types/spread/spreadUnion2.ts(11,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' has type '{} | { a: number; } | { b: number; } | { a: number; b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 9:4, but here has type '{}'. +tests/cases/conformance/types/spread/spreadUnion2.ts(12,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' has type '{} | { a: number; } | { b: number; } | { a: number; b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 9:4, but here has type '{}'. +tests/cases/conformance/types/spread/spreadUnion2.ts(15,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o4' has type '{} | { a: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 13:4, but here has type '{}'. +tests/cases/conformance/types/spread/spreadUnion2.ts(18,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'o5' has type '{} | { b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 16:4, but here has type '{}'. + + +==== tests/cases/conformance/types/spread/spreadUnion2.ts (6 errors) ==== + declare const undefinedUnion: { a: number } | undefined; + declare const nullUnion: { b: number } | null; + + var o1: {} | { a: number }; + var o1 = { ...undefinedUnion }; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o1' has type '{} | { a: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 3:4, but here has type '{}'. + + var o2: {} | { b: number }; + var o2 = { ...nullUnion }; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o2' has type '{} | { b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 6:4, but here has type '{}'. + + var o3: {} | { a: number } | { b: number } | { a: number, b: number }; + var o3 = { ...undefinedUnion, ...nullUnion }; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' has type '{} | { a: number; } | { b: number; } | { a: number; b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 9:4, but here has type '{}'. + var o3 = { ...nullUnion, ...undefinedUnion }; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o3' has type '{} | { a: number; } | { b: number; } | { a: number; b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 9:4, but here has type '{}'. + + var o4: {} | { a: number }; + var o4 = { ...undefinedUnion, ...undefinedUnion }; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o4' has type '{} | { a: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 13:4, but here has type '{}'. + + var o5: {} | { b: number }; + var o5 = { ...nullUnion, ...nullUnion }; + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'o5' has type '{} | { b: number; }' at tests/cases/conformance/types/spread/spreadUnion2.ts 16:4, but here has type '{}'. + + \ No newline at end of file diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt index b7c5969794639..b1fa3316d34e0 100644 --- a/tests/baselines/reference/spreadUnion3.errors.txt +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -2,8 +2,7 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(2,5): error TS2322: Type '{ Type '{ y: number; }' is not assignable to type '{ y: string; }'. Types of property 'y' are incompatible. Type 'number' is not assignable to type 'string'. -tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. - Property 'a' does not exist on type '{}'. +tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{}'. tests/cases/conformance/types/spread/spreadUnion3.ts(17,11): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Spread types may only be created from object types. @@ -24,8 +23,7 @@ tests/cases/conformance/types/spread/spreadUnion3.ts(18,11): error TS2698: Sprea let b = { ...t }; let c: number = b.a; // might not have 'a' ~ -!!! error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. -!!! error TS2339: Property 'a' does not exist on type '{}'. +!!! error TS2339: Property 'a' does not exist on type '{}'. } g() g(undefined) diff --git a/tests/baselines/reference/spreadUnion3.types b/tests/baselines/reference/spreadUnion3.types index a457307aad1c0..940ec96f5b7c3 100644 --- a/tests/baselines/reference/spreadUnion3.types +++ b/tests/baselines/reference/spreadUnion3.types @@ -24,14 +24,14 @@ function g(t?: { a: number } | null): void { >null : null let b = { ...t }; ->b : {} | {} | { a: number; } +>b : {} >{ ...t } : {} | {} | { a: number; } >t : { a: number; } | null | undefined let c: number = b.a; // might not have 'a' >c : number >b.a : any ->b : {} | {} | { a: number; } +>b : {} >a : any } g() diff --git a/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types b/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types index 23ac78ec01376..e2f294343a573 100644 --- a/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types +++ b/tests/baselines/reference/subtypesOfTypeParameterWithConstraints2.types @@ -676,14 +676,14 @@ function f21(x: T) { var r20 = true ? {} : x; // ok >r20 : {} ->true ? {} : x : {} +>true ? {} : x : T | {} >true : true >{} : {} >x : T var r20 = true ? x : {}; // ok >r20 : {} ->true ? x : {} : {} +>true ? x : {} : T | {} >true : true >x : T >{} : {} diff --git a/tests/baselines/reference/symbolType1.types b/tests/baselines/reference/symbolType1.types index 5974b9b801c22..d55c95d3685cc 100644 --- a/tests/baselines/reference/symbolType1.types +++ b/tests/baselines/reference/symbolType1.types @@ -13,8 +13,8 @@ Symbol instanceof Symbol(); (Symbol() || {}) instanceof Object; // This one should be okay, it's a valid way of distinguishing types >(Symbol() || {}) instanceof Object : boolean ->(Symbol() || {}) : {} ->Symbol() || {} : {} +>(Symbol() || {}) : symbol | {} +>Symbol() || {} : symbol | {} >Symbol() : symbol >Symbol : SymbolConstructor >{} : {} @@ -23,8 +23,8 @@ Symbol instanceof Symbol(); Symbol instanceof (Symbol() || {}); >Symbol instanceof (Symbol() || {}) : boolean >Symbol : SymbolConstructor ->(Symbol() || {}) : {} ->Symbol() || {} : {} +>(Symbol() || {}) : symbol | {} +>Symbol() || {} : symbol | {} >Symbol() : symbol >Symbol : SymbolConstructor >{} : {} diff --git a/tests/baselines/reference/symbolType11.types b/tests/baselines/reference/symbolType11.types index ec474dcdb54a6..bbee323b065b2 100644 --- a/tests/baselines/reference/symbolType11.types +++ b/tests/baselines/reference/symbolType11.types @@ -33,7 +33,7 @@ s || 1; >1 : 1 ({}) || s; ->({}) || s : {} +>({}) || s : symbol | {} >({}) : {} >{} : {} >s : symbol diff --git a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.errors.txt b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.errors.txt index 16ad335803806..7e4062ae10a00 100644 --- a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.errors.txt +++ b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference.ts(62,36): error TS2345: Argument of type '0' is not assignable to parameter of type '""'. -tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference.ts(75,79): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: Date; }'. - Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: Date; }'. +tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference.ts(76,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference.ts 74:4, but here has type '{}'. ==== tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference.ts (2 errors) ==== @@ -81,10 +80,9 @@ tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference } var a9e = someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }`; - ~~~~~ -!!! error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: Date; }'. -!!! error TS2345: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: Date; }'. var a9e: {}; + ~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference.ts 74:4, but here has type '{}'. // Generic tag with multiple parameters of generic type passed arguments with a single best common type var a9d = someGenerics9 `${ { x: 3 }}${ { x: 6 }}${ { x: 6 } }`; diff --git a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.types b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.types index 5c98fb4e7dee5..d1be9c77cb984 100644 --- a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.types +++ b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInference.types @@ -395,8 +395,8 @@ interface A92 { } var a9e = someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }`; ->a9e : any ->someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }` : any +>a9e : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } +>someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }` : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } >someGenerics9 : (strs: TemplateStringsArray, a: T, b: T, c: T) => T >`${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }` : string >undefined : undefined @@ -413,7 +413,7 @@ var a9e = someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: >'' : "" var a9e: {}; ->a9e : any +>a9e : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } // Generic tag with multiple parameters of generic type passed arguments with a single best common type var a9d = someGenerics9 `${ { x: 3 }}${ { x: 6 }}${ { x: 6 } }`; diff --git a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.errors.txt b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.errors.txt index 0d43f3d39b2e6..9112a0542b54e 100644 --- a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.errors.txt +++ b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInferenceES6.ts(62,36): error TS2345: Argument of type '0' is not assignable to parameter of type '""'. -tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInferenceES6.ts(75,79): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: Date; }'. - Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: Date; }'. +tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInferenceES6.ts(76,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInferenceES6.ts 74:4, but here has type '{}'. ==== tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInferenceES6.ts (2 errors) ==== @@ -81,10 +80,9 @@ tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInference } var a9e = someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }`; - ~~~~~ -!!! error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: Date; }'. -!!! error TS2345: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: Date; }'. var a9e: {}; + ~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/es6/templates/taggedTemplateStringsTypeArgumentInferenceES6.ts 74:4, but here has type '{}'. // Generic tag with multiple parameters of generic type passed arguments with a single best common type var a9d = someGenerics9 `${ { x: 3 }}${ { x: 6 }}${ { x: 6 } }`; diff --git a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.types b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.types index 9f7df761320a1..e0a1d33937655 100644 --- a/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.types +++ b/tests/baselines/reference/taggedTemplateStringsTypeArgumentInferenceES6.types @@ -395,8 +395,8 @@ interface A92 { } var a9e = someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }`; ->a9e : any ->someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }` : any +>a9e : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } +>someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }` : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } >someGenerics9 : (strs: TemplateStringsArray, a: T, b: T, c: T) => T >`${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: '' } }` : string >undefined : undefined @@ -413,7 +413,7 @@ var a9e = someGenerics9 `${ undefined }${ { x: 6, z: new Date() } }${ { x: 6, y: >'' : "" var a9e: {}; ->a9e : any +>a9e : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } // Generic tag with multiple parameters of generic type passed arguments with a single best common type var a9d = someGenerics9 `${ { x: 3 }}${ { x: 6 }}${ { x: 6 } }`; diff --git a/tests/baselines/reference/typeArgInference2.errors.txt b/tests/baselines/reference/typeArgInference2.errors.txt deleted file mode 100644 index 41fdd9b0783a6..0000000000000 --- a/tests/baselines/reference/typeArgInference2.errors.txt +++ /dev/null @@ -1,20 +0,0 @@ -tests/cases/compiler/typeArgInference2.ts(12,52): error TS2345: Argument of type '{ name: string; b: number; }' is not assignable to parameter of type '{ name: string; a: number; }'. - Object literal may only specify known properties, and 'b' does not exist in type '{ name: string; a: number; }'. - - -==== tests/cases/compiler/typeArgInference2.ts (1 errors) ==== - interface Item { - name: string; - } - - declare function foo(x?: T, y?: T): T; - - var z1 = foo(null); // any - var z2 = foo(); // Item - var z3 = foo({ name: null }); // { name: any } - var z4 = foo({ name: "abc" }); // { name: string } - var z5 = foo({ name: "abc", a: 5 }); // { name: string; a: number } - var z6 = foo({ name: "abc", a: 5 }, { name: "def", b: 5 }); // error - ~~~~ -!!! error TS2345: Argument of type '{ name: string; b: number; }' is not assignable to parameter of type '{ name: string; a: number; }'. -!!! error TS2345: Object literal may only specify known properties, and 'b' does not exist in type '{ name: string; a: number; }'. \ No newline at end of file diff --git a/tests/baselines/reference/typeArgInference2.types b/tests/baselines/reference/typeArgInference2.types index 12262c1896fe4..2b985a7c208b9 100644 --- a/tests/baselines/reference/typeArgInference2.types +++ b/tests/baselines/reference/typeArgInference2.types @@ -54,8 +54,8 @@ var z5 = foo({ name: "abc", a: 5 }); // { name: string; a: number } >5 : 5 var z6 = foo({ name: "abc", a: 5 }, { name: "def", b: 5 }); // error ->z6 : any ->foo({ name: "abc", a: 5 }, { name: "def", b: 5 }) : any +>z6 : { name: string; a: number; b?: undefined; } | { name: string; b: number; a?: undefined; } +>foo({ name: "abc", a: 5 }, { name: "def", b: 5 }) : { name: string; a: number; b?: undefined; } | { name: string; b: number; a?: undefined; } >foo : (x?: T, y?: T) => T >{ name: "abc", a: 5 } : { name: string; a: number; } >name : string diff --git a/tests/baselines/reference/typeArgumentInference.errors.txt b/tests/baselines/reference/typeArgumentInference.errors.txt index 4daa055d20ac5..cfed6cc640bda 100644 --- a/tests/baselines/reference/typeArgumentInference.errors.txt +++ b/tests/baselines/reference/typeArgumentInference.errors.txt @@ -1,6 +1,5 @@ tests/cases/conformance/expressions/functionCalls/typeArgumentInference.ts(68,29): error TS2345: Argument of type '0' is not assignable to parameter of type '""'. -tests/cases/conformance/expressions/functionCalls/typeArgumentInference.ts(82,69): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: Date; }'. - Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: Date; }'. +tests/cases/conformance/expressions/functionCalls/typeArgumentInference.ts(83,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/expressions/functionCalls/typeArgumentInference.ts 81:4, but here has type '{}'. tests/cases/conformance/expressions/functionCalls/typeArgumentInference.ts(84,74): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type 'A92'. Object literal may only specify known properties, and 'y' does not exist in type 'A92'. @@ -90,10 +89,9 @@ tests/cases/conformance/expressions/functionCalls/typeArgumentInference.ts(84,74 z?: Date; } var a9e = someGenerics9(undefined, { x: 6, z: new Date() }, { x: 6, y: '' }); - ~~~~~ -!!! error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: Date; }'. -!!! error TS2345: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: Date; }'. var a9e: {}; + ~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/expressions/functionCalls/typeArgumentInference.ts 81:4, but here has type '{}'. var a9f = someGenerics9(undefined, { x: 6, z: new Date() }, { x: 6, y: '' }); ~~~~~ !!! error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type 'A92'. diff --git a/tests/baselines/reference/typeArgumentInference.types b/tests/baselines/reference/typeArgumentInference.types index 02326834d3b25..1f39235ae36ff 100644 --- a/tests/baselines/reference/typeArgumentInference.types +++ b/tests/baselines/reference/typeArgumentInference.types @@ -421,8 +421,8 @@ interface A92 { >Date : Date } var a9e = someGenerics9(undefined, { x: 6, z: new Date() }, { x: 6, y: '' }); ->a9e : any ->someGenerics9(undefined, { x: 6, z: new Date() }, { x: 6, y: '' }) : any +>a9e : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } +>someGenerics9(undefined, { x: 6, z: new Date() }, { x: 6, y: '' }) : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } >someGenerics9 : (a: T, b: T, c: T) => T >undefined : undefined >{ x: 6, z: new Date() } : { x: number; z: Date; } @@ -438,7 +438,7 @@ var a9e = someGenerics9(undefined, { x: 6, z: new Date() }, { x: 6, y: '' }); >'' : "" var a9e: {}; ->a9e : any +>a9e : { x: number; z: Date; y?: undefined; } | { x: number; y: string; z?: undefined; } var a9f = someGenerics9(undefined, { x: 6, z: new Date() }, { x: 6, y: '' }); >a9f : any diff --git a/tests/baselines/reference/typeArgumentInferenceConstructSignatures.errors.txt b/tests/baselines/reference/typeArgumentInferenceConstructSignatures.errors.txt index da5558afdf739..ef0c93f20cda5 100644 --- a/tests/baselines/reference/typeArgumentInferenceConstructSignatures.errors.txt +++ b/tests/baselines/reference/typeArgumentInferenceConstructSignatures.errors.txt @@ -12,8 +12,7 @@ tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstruct tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts(106,33): error TS2345: Argument of type '0' is not assignable to parameter of type '""'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts(118,9): error TS2304: Cannot find name 'Window'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts(120,51): error TS2304: Cannot find name 'window'. -tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts(120,69): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: any; }'. - Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: any; }'. +tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts(121,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts 119:4, but here has type '{}'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts(122,56): error TS2304: Cannot find name 'window'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts(122,74): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type 'A92'. Object literal may only specify known properties, and 'y' does not exist in type 'A92'. @@ -162,10 +161,9 @@ tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstruct var a9e = new someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); ~~~~~~ !!! error TS2304: Cannot find name 'window'. - ~~~~~ -!!! error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: any; }'. -!!! error TS2345: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: any; }'. var a9e: {}; + ~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceConstructSignatures.ts 119:4, but here has type '{}'. var a9f = new someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); ~~~~~~ !!! error TS2304: Cannot find name 'window'. diff --git a/tests/baselines/reference/typeArgumentInferenceConstructSignatures.types b/tests/baselines/reference/typeArgumentInferenceConstructSignatures.types index 8981c077b488e..04dae1dafa758 100644 --- a/tests/baselines/reference/typeArgumentInferenceConstructSignatures.types +++ b/tests/baselines/reference/typeArgumentInferenceConstructSignatures.types @@ -524,8 +524,8 @@ interface A92 { >Window : No type information available! } var a9e = new someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); ->a9e : any ->new someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }) : any +>a9e : { x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; } +>new someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }) : { x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; } >someGenerics9 : someGenerics9 >undefined : undefined >{ x: 6, z: window } : { x: number; z: any; } @@ -540,7 +540,7 @@ var a9e = new someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); >'' : "" var a9e: {}; ->a9e : any +>a9e : { x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; } var a9f = new someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); >a9f : any diff --git a/tests/baselines/reference/typeArgumentInferenceWithConstraints.errors.txt b/tests/baselines/reference/typeArgumentInferenceWithConstraints.errors.txt index 6cc81171bccc8..2b3053906896d 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithConstraints.errors.txt +++ b/tests/baselines/reference/typeArgumentInferenceWithConstraints.errors.txt @@ -17,8 +17,7 @@ tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConst tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts(73,29): error TS2345: Argument of type '0' is not assignable to parameter of type '""'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts(85,9): error TS2304: Cannot find name 'Window'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts(87,47): error TS2304: Cannot find name 'window'. -tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts(87,65): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: any; }'. - Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: any; }'. +tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts(88,5): error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts 86:4, but here has type '{}'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts(89,52): error TS2304: Cannot find name 'window'. tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts(89,70): error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type 'A92'. Object literal may only specify known properties, and 'y' does not exist in type 'A92'. @@ -144,10 +143,9 @@ tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConst var a9e = someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); ~~~~~~ !!! error TS2304: Cannot find name 'window'. - ~~~~~ -!!! error TS2345: Argument of type '{ x: number; y: string; }' is not assignable to parameter of type '{ x: number; z: any; }'. -!!! error TS2345: Object literal may only specify known properties, and 'y' does not exist in type '{ x: number; z: any; }'. var a9e: {}; + ~~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'a9e' has type '{ x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; }' at tests/cases/conformance/expressions/functionCalls/typeArgumentInferenceWithConstraints.ts 86:4, but here has type '{}'. var a9f = someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); ~~~~~~ !!! error TS2304: Cannot find name 'window'. diff --git a/tests/baselines/reference/typeArgumentInferenceWithConstraints.types b/tests/baselines/reference/typeArgumentInferenceWithConstraints.types index 4e120b70eb531..4ca65f02b02b8 100644 --- a/tests/baselines/reference/typeArgumentInferenceWithConstraints.types +++ b/tests/baselines/reference/typeArgumentInferenceWithConstraints.types @@ -464,8 +464,8 @@ interface A92 { >Window : No type information available! } var a9e = someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); ->a9e : any ->someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }) : any +>a9e : { x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; } +>someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }) : { x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; } >someGenerics9 : (a: T, b: T, c: T) => T >undefined : undefined >{ x: 6, z: window } : { x: number; z: any; } @@ -480,7 +480,7 @@ var a9e = someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); >'' : "" var a9e: {}; ->a9e : any +>a9e : { x: number; z: any; y?: undefined; } | { x: number; y: string; z?: undefined; } var a9f = someGenerics9(undefined, { x: 6, z: window }, { x: 6, y: '' }); >a9f : any diff --git a/tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts b/tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts new file mode 100644 index 0000000000000..1166e1c6ed3b6 --- /dev/null +++ b/tests/cases/conformance/expressions/objectLiterals/objectLiteralNormalization.ts @@ -0,0 +1,52 @@ +// @strict: true +// @declaration: true + +// Object literals in unions are normalized upon widening +let a1 = [{ a: 0 }, { a: 1, b: "x" }, { a: 2, b: "y", c: true }][0]; +a1.a; // number +a1.b; // string | undefined +a1.c; // boolean | undefined +a1 = { a: 1 }; +a1 = { a: 0, b: 0 }; // Error +a1 = { b: "y" }; // Error +a1 = { c: true }; // Error + +let a2 = [{ a: 1, b: 2 }, { a: "abc" }, {}][0]; +a2.a; // string | number | undefined +a2.b; // number | undefined +a2 = { a: 10, b: 20 }; +a2 = { a: "def" }; +a2 = {}; +a2 = { a: "def", b: 20 }; // Error +a2 = { a: 1 }; // Error + +// Object literals containing spreads are not normalized +declare let b1: { a: string, b: string } | { b: string, c: string }; +let b2 = { ...b1, z: 55 }; +let b3 = { ...b2 }; + +// Before widening {} acts like { [x: string]: undefined }, which is a +// subtype of types with all optional properties +declare let opts: { foo?: string, bar?: string, baz?: boolean }; +let c1 = !true ? {} : opts; +let c2 = !true ? opts : {}; +let c3 = !true ? { a: 0, b: 0 } : {}; +let c4 = !true ? {} : { a: 0, b: 0 }; + +// Normalization applies to nested properties +let d1 = [{ kind: 'a', pos: { x: 0, y: 0 } }, { kind: 'b', pos: !true ? { a: "x" } : { b: 0 } }][0]; +d1.kind; +d1.pos; +d1.pos.x; +d1.pos.y; +d1.pos.a; +d1.pos.b; + +declare function f(...items: T[]): T; +declare let data: { a: 1, b: "abc", c: true }; + +// Object literals are inferred as a single normalized union type +let e1 = f({ a: 1, b: 2 }, { a: "abc" }, {}); +let e2 = f({}, { a: "abc" }, { a: 1, b: 2 }); +let e3 = f(data, { a: 2 }); +let e4 = f({ a: 2 }, data);