From 3cf0bf739eda6016280239d6ba6888fbbbf3bebd Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 3 Jan 2018 11:36:04 -0800 Subject: [PATCH 01/14] Union literal computed properties lift to union Still uses getSpreadType (with modifications) for combining multiple unioned computed properties. This likely has problems that will be exposed by more tests after I write them. --- src/compiler/checker.ts | 160 +++++++++++++++++++++++++--------------- 1 file changed, 99 insertions(+), 61 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 10bbe62289610..16543d66ea92b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5993,9 +5993,13 @@ namespace ts { getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly); } - function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo): IndexInfo { - return info1 && info2 && createIndexInfo( - getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly); + function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo, looseIndexes: boolean): IndexInfo { + if (info1 && info2) { + return createIndexInfo(getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly); + } + if (looseIndexes) { + return info1 ? info1 : info2 ? info2 : undefined; + } } function includeMixinType(type: Type, types: Type[], index: number): Type { @@ -8355,7 +8359,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol, propagatedFlags: TypeFlags): Type { + function getSpreadType(left: Type, right: Type, symbol: Symbol, propagatedFlags: TypeFlags, looseIndexes: boolean): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -8366,10 +8370,10 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - return mapType(left, t => getSpreadType(t, right, symbol, propagatedFlags)); + return mapType(left, t => getSpreadType(t, right, symbol, propagatedFlags, looseIndexes)); } if (right.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t, symbol, propagatedFlags)); + return mapType(right, t => getSpreadType(left, t, symbol, propagatedFlags, looseIndexes)); } if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive)) { return left; @@ -8385,8 +8389,8 @@ namespace ts { numberIndexInfo = getIndexInfoOfType(right, IndexKind.Number); } else { - stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String)); - numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number)); + stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String), looseIndexes); + numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number), looseIndexes); } for (const rightProp of getPropertiesOfType(right)) { @@ -14618,13 +14622,14 @@ namespace ts { let patternWithComputedProperties = false; let hasComputedStringProperty = false; let hasComputedNumberProperty = false; + let hasUnionedComputedProperty = false; const isInJSFile = isInJavaScriptFile(node); let offset = 0; for (let i = 0; i < node.properties.length; i++) { const memberDecl = node.properties[i]; let member = getSymbolOfNode(memberDecl); - let literalName: __String | undefined; + let literalName: __String[] | __String | undefined; if (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || isObjectLiteralMethod(memberDecl)) { @@ -14638,7 +14643,10 @@ namespace ts { if (memberDecl.name.kind === SyntaxKind.ComputedPropertyName) { const t = checkComputedPropertyName(memberDecl.name); if (t.flags & TypeFlags.Literal) { - literalName = escapeLeadingUnderscores("" + (t as LiteralType).value); + literalName = getLiteralPropertyName(t); + } + else if (t.flags & TypeFlags.Union && (t as UnionType).types.every(t2 => !!(t2.flags & TypeFlags.Literal))) { + literalName = (t as UnionType).types.map(getLiteralPropertyName); } } type = checkPropertyAssignment(memberDecl, checkMode); @@ -14657,66 +14665,27 @@ namespace ts { } typeFlags |= type.flags; - - const nameType = hasLateBindableName(memberDecl) ? checkComputedPropertyName(memberDecl.name) : undefined; - const prop = nameType && isTypeUsableAsLateBoundName(nameType) - ? createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType), CheckFlags.Late) - : createSymbol(SymbolFlags.Property | member.flags, literalName || member.escapedName); - - if (inDestructuringPattern) { - // If object literal is an assignment pattern and if the assignment pattern specifies a default value - // for the property, make the property optional. - const isOptional = - (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue((memberDecl).initializer)) || - (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && (memberDecl).objectAssignmentInitializer); - if (isOptional) { - prop.flags |= SymbolFlags.Optional; - } - if (!literalName && hasDynamicName(memberDecl)) { - patternWithComputedProperties = true; - } - } - else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { - // If object literal is contextually typed by the implied type of a binding pattern, and if the - // binding pattern specifies a default value for the property, make the property optional. - const impliedProp = getPropertyOfType(contextualType, member.escapedName); - if (impliedProp) { - prop.flags |= impliedProp.flags & SymbolFlags.Optional; - } - - else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, IndexKind.String)) { - error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, - symbolToString(member), typeToString(contextualType)); - } - } - prop.declarations = member.declarations; - prop.parent = member.parent; - if (member.valueDeclaration) { - prop.valueDeclaration = member.valueDeclaration; + if (isArray(literalName)) { + hasUnionedComputedProperty = true; + next(createUnion(memberDecl, member, literalName, type)); + continue; } - prop.type = type; - prop.target = member; - member = prop; + member = createProperty(memberDecl, member, literalName, type); } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { if (languageVersion < ScriptTarget.ES2015) { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags); - propertiesArray = []; - propertiesTable = createSymbolTable(); - hasComputedStringProperty = false; - hasComputedNumberProperty = false; - typeFlags = 0; + next(getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ false)); } const type = checkExpression((memberDecl as SpreadAssignment).expression); if (!isValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } - spread = getSpreadType(spread, type, node.symbol, propagatedFlags); + spread = getSpreadType(spread, type, node.symbol, propagatedFlags, /*looseIndexes*/ false); offset = i + 1; continue; } @@ -14761,13 +14730,82 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags); + // TODO: This is now insufficient; sometimes the spread is a result of a computed property with type union of literal type + // getSpreadType will *sometimes* work here, but not always + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ hasUnionedComputedProperty); } return spread; } return createObjectLiteralType(); + function getLiteralPropertyName(type: Type): __String { + if (type.flags & TypeFlags.Intrinsic) { + return (type as IntrinsicType).intrinsicName as __String; + } + return escapeLeadingUnderscores("" + (type as LiteralType).value); + } + + function next(type: Type) { + spread = type; + propertiesArray = []; + propertiesTable = createSymbolTable(); + } + + function createUnion(memberDecl: ObjectLiteralElementLike, member: Symbol, literalNames: __String[], type: Type) { + const types: Type[] = []; + for (const literalName of literalNames) { + const prop = createProperty(memberDecl, member, literalName, type); + propertiesArray.push(prop); + propertiesTable.set(prop.escapedName, prop); + types.push(createObjectLiteralType()); + propertiesArray.pop(); + propertiesTable.delete(prop.escapedName); // Probably fine?? + } + // TODO: Spread maybe isn't right, because it's so weird + return getSpreadType(spread, getUnionType(types), node.symbol, propagatedFlags, /*looseIndexes*/ true); + } + + // TODO: Probably don't need the second parameter + function createProperty(memberDecl: ObjectLiteralElementLike, member: Symbol, literalName: __String, type: Type) { + const nameType = hasLateBindableName(memberDecl) ? checkComputedPropertyName(memberDecl.name) : undefined; + const prop = nameType && isTypeUsableAsLateBoundName(nameType) + ? createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType), CheckFlags.Late) + : createSymbol(SymbolFlags.Property | member.flags, literalName || member.escapedName); + if (inDestructuringPattern) { + // If object literal is an assignment pattern and if the assignment pattern specifies a default value + // for the property, make the property optional. + const isOptional = (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue((memberDecl).initializer)) || + (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && (memberDecl).objectAssignmentInitializer); + if (isOptional) { + + prop.flags |= SymbolFlags.Optional; + } + if (!literalName && hasDynamicName(memberDecl)) { + patternWithComputedProperties = true; + } + } + else if (contextualTypeHasPattern && !(getObjectFlags(contextualType) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) { + // If object literal is contextually typed by the implied type of a binding pattern, and if the + // binding pattern specifies a default value for the property, make the property optional. + const impliedProp = getPropertyOfType(contextualType, member.escapedName); + if (impliedProp) { + prop.flags |= impliedProp.flags & SymbolFlags.Optional; + } + else if (!compilerOptions.suppressExcessPropertyErrors && !getIndexInfoOfType(contextualType, IndexKind.String)) { + error(memberDecl.name, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, symbolToString(member), typeToString(contextualType)); + } + } + prop.declarations = member.declarations; + prop.parent = member.parent; + if (member.valueDeclaration) { + prop.valueDeclaration = member.valueDeclaration; + } + prop.type = type; + prop.target = member; + return prop; + } + function createObjectLiteralType() { const stringIndexInfo = isJSObjectLiteral ? jsObjectLiteralIndexInfo : hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined; const numberIndexInfo = hasComputedNumberProperty && !isJSObjectLiteral ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined; @@ -14894,7 +14932,7 @@ namespace ts { else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); attributesTable = createSymbolTable(); } const exprType = checkExpressionCached(attributeDecl.expression, checkMode); @@ -14902,7 +14940,7 @@ namespace ts { hasSpreadAnyType = true; } if (isValidSpreadType(exprType)) { - spread = getSpreadType(spread, exprType, openingLikeElement.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, exprType, openingLikeElement.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); } else { typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; @@ -14912,7 +14950,7 @@ namespace ts { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); } } @@ -14937,7 +14975,7 @@ namespace ts { createArrayType(getUnionType(childrenTypes)); const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); - spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), attributes.symbol, TypeFlags.JsxAttributes); + spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), attributes.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); } } From b39688c278a5fdf262d1a155cb45cdbc3efdde3b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Wed, 3 Jan 2018 12:18:37 -0800 Subject: [PATCH 02/14] Test literal union computed property lifting --- .../computedPropertyNames5_ES5.types | 4 +- .../computedPropertyNames5_ES6.types | 4 +- .../computedPropertyUnionLiftsToUnionType.js | 45 ++++++++++++++++ ...putedPropertyUnionLiftsToUnionType.symbols | 46 +++++++++++++++++ ...omputedPropertyUnionLiftsToUnionType.types | 51 +++++++++++++++++++ .../parserComputedPropertyName41.types | 4 +- .../computedPropertyUnionLiftsToUnionType.ts | 25 +++++++++ 7 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js create mode 100644 tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols create mode 100644 tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types create mode 100644 tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts diff --git a/tests/baselines/reference/computedPropertyNames5_ES5.types b/tests/baselines/reference/computedPropertyNames5_ES5.types index 943df91416686..027bfd2acb040 100644 --- a/tests/baselines/reference/computedPropertyNames5_ES5.types +++ b/tests/baselines/reference/computedPropertyNames5_ES5.types @@ -3,8 +3,8 @@ var b: boolean; >b : boolean var v = { ->v : { [x: string]: number; [x: number]: any; [true]: number; } ->{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; [true]: number; } +>v : { [x: string]: number; [x: number]: any; [true]: number; } | { [x: string]: number; [x: number]: any; [true]: number; [b]: number; } +>{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; [true]: number; } | { [x: string]: number; [x: number]: null; [true]: number; [b]: number; } [b]: 0, >b : boolean diff --git a/tests/baselines/reference/computedPropertyNames5_ES6.types b/tests/baselines/reference/computedPropertyNames5_ES6.types index 18b522b4f6e0e..c160d3d44e8ac 100644 --- a/tests/baselines/reference/computedPropertyNames5_ES6.types +++ b/tests/baselines/reference/computedPropertyNames5_ES6.types @@ -3,8 +3,8 @@ var b: boolean; >b : boolean var v = { ->v : { [x: string]: number; [x: number]: any; [true]: number; } ->{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; [true]: number; } +>v : { [x: string]: number; [x: number]: any; [true]: number; } | { [x: string]: number; [x: number]: any; [true]: number; [b]: number; } +>{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; [true]: number; } | { [x: string]: number; [x: number]: null; [true]: number; [b]: number; } [b]: 0, >b : boolean diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js new file mode 100644 index 0000000000000..762391d301c44 --- /dev/null +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js @@ -0,0 +1,45 @@ +//// [computedPropertyUnionLiftsToUnionType.ts] +declare var ab: 'a' | 'b'; +declare var cd: 'c' | 'd'; +// More cases: +// add spreads +// other literal types: number, boolean, enum (string and number) +// multiple unions +// union, spread (with union inside), union +// methods and other stuff that would get mangled by spread (since I use spread internally) +const x: { a: string } | { b: string } = { [ab]: 'hi' } +const y: { a: string, c: string } | { a: string, d: string } | { b: string, c: string } | { b: string, d: string } = + { [ab]: 'hi', [cd]: 'there' } + +// in destructuring???!! +/* +declare let o: { [t]: string } +declare let u: { a: string } | { b: string } +const { [t]: doo } = o +const { [t]: duo } = u +var t: 'a' | 'b' = doo +var t: 'a' | 'b' = duo +*/ + + + + +//// [computedPropertyUnionLiftsToUnionType.js] +// More cases: +// add spreads +// other literal types: number, boolean, enum (string and number) +// multiple unions +// union, spread (with union inside), union +// methods and other stuff that would get mangled by spread (since I use spread internally) +var x = (_a = {}, _a[ab] = 'hi', _a); +var y = (_b = {}, _b[ab] = 'hi', _b[cd] = 'there', _b); +var _a, _b; +// in destructuring???!! +/* +declare let o: { [t]: string } +declare let u: { a: string } | { b: string } +const { [t]: doo } = o +const { [t]: duo } = u +var t: 'a' | 'b' = doo +var t: 'a' | 'b' = duo +*/ diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols new file mode 100644 index 0000000000000..9dd217d6da13b --- /dev/null +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols @@ -0,0 +1,46 @@ +=== tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts === +declare var ab: 'a' | 'b'; +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) + +declare var cd: 'c' | 'd'; +>cd : Symbol(cd, Decl(computedPropertyUnionLiftsToUnionType.ts, 1, 11)) + +// More cases: +// add spreads +// other literal types: number, boolean, enum (string and number) +// multiple unions +// union, spread (with union inside), union +// methods and other stuff that would get mangled by spread (since I use spread internally) +const x: { a: string } | { b: string } = { [ab]: 'hi' } +>x : Symbol(x, Decl(computedPropertyUnionLiftsToUnionType.ts, 8, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 8, 10)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 8, 26)) +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) + +const y: { a: string, c: string } | { a: string, d: string } | { b: string, c: string } | { b: string, d: string } = +>y : Symbol(y, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 10)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 21)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 37)) +>d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 48)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 64)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 75)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 91)) +>d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 102)) + + { [ab]: 'hi', [cd]: 'there' } +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>cd : Symbol(cd, Decl(computedPropertyUnionLiftsToUnionType.ts, 1, 11)) + +// in destructuring???!! +/* +declare let o: { [t]: string } +declare let u: { a: string } | { b: string } +const { [t]: doo } = o +const { [t]: duo } = u +var t: 'a' | 'b' = doo +var t: 'a' | 'b' = duo +*/ + + + diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types new file mode 100644 index 0000000000000..8143d159c3df2 --- /dev/null +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types @@ -0,0 +1,51 @@ +=== tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts === +declare var ab: 'a' | 'b'; +>ab : "a" | "b" + +declare var cd: 'c' | 'd'; +>cd : "c" | "d" + +// More cases: +// add spreads +// other literal types: number, boolean, enum (string and number) +// multiple unions +// union, spread (with union inside), union +// methods and other stuff that would get mangled by spread (since I use spread internally) +const x: { a: string } | { b: string } = { [ab]: 'hi' } +>x : { a: string; } | { b: string; } +>a : string +>b : string +>{ [ab]: 'hi' } : { [ab]: string; } | { [ab]: string; } +>ab : "a" | "b" +>'hi' : "hi" + +const y: { a: string, c: string } | { a: string, d: string } | { b: string, c: string } | { b: string, d: string } = +>y : { a: string; c: string; } | { a: string; d: string; } | { b: string; c: string; } | { b: string; d: string; } +>a : string +>c : string +>a : string +>d : string +>b : string +>c : string +>b : string +>d : string + + { [ab]: 'hi', [cd]: 'there' } +>{ [ab]: 'hi', [cd]: 'there' } : { [cd]: string; [ab]: string; } | { [cd]: string; [ab]: string; } | { [cd]: string; [ab]: string; } | { [cd]: string; [ab]: string; } +>ab : "a" | "b" +>'hi' : "hi" +>cd : "c" | "d" +>'there' : "there" + +// in destructuring???!! +/* +declare let o: { [t]: string } +declare let u: { a: string } | { b: string } +const { [t]: doo } = o +const { [t]: duo } = u +var t: 'a' | 'b' = doo +var t: 'a' | 'b' = duo +*/ + + + diff --git a/tests/baselines/reference/parserComputedPropertyName41.types b/tests/baselines/reference/parserComputedPropertyName41.types index 2ef1a813a585e..5300d79e4b082 100644 --- a/tests/baselines/reference/parserComputedPropertyName41.types +++ b/tests/baselines/reference/parserComputedPropertyName41.types @@ -1,7 +1,7 @@ === tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName41.ts === var v = { ->v : { [x: string]: boolean; } ->{ [0 in []]: true} : { [x: string]: boolean; } +>v : { [0 in []]: boolean; } | { [0 in []]: boolean; } +>{ [0 in []]: true} : { [0 in []]: boolean; } | { [0 in []]: boolean; } [0 in []]: true >0 in [] : boolean diff --git a/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts new file mode 100644 index 0000000000000..3e315c349c122 --- /dev/null +++ b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts @@ -0,0 +1,25 @@ +declare var ab: 'a' | 'b'; +declare var cd: 'c' | 'd'; +// More cases: +// add spreads +// other literal types: number, boolean, enum (string and number) +// multiple unions +// union, spread (with union inside), union +// methods and other stuff that would get mangled by spread (since I use spread internally) +const x: { a: string } | { b: string } = { [ab]: 'hi' } +const y: { a: string, m: number, c: string } + | { a: string, m: number, d: string } + | { b: string, m: number, c: string } + | { b: string, m: number, d: string } = { [ab]: 'hi', m: 1, [cd]: 'there' } + +// in destructuring???!! +/* +declare let o: { [t]: string } +declare let u: { a: string } | { b: string } +const { [t]: doo } = o +const { [t]: duo } = u +var t: 'a' | 'b' = doo +var t: 'a' | 'b' = duo +*/ + + From d407c92ad001026b18e57fc8b06df0004a2035a4 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 4 Jan 2018 15:46:26 -0800 Subject: [PATCH 03/14] Print known constants in computed property types Also improve some names --- src/compiler/checker.ts | 49 +++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 16543d66ea92b..b87cc632d4bbc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2094,7 +2094,7 @@ namespace ts { } // A reserved member name starts with two underscores, but the third character cannot be an underscore - // or the @ symbol. A third underscore indicates an escaped form of an identifer that started + // or the @ symbol. A third underscore indicates an escaped form of an identifier that started // with at least two underscores. The @ character indicates that the name is denoted by a well known ES // Symbol instance. function isReservedMemberName(name: __String) { @@ -3187,6 +3187,13 @@ namespace ts { const declaration = symbol.declarations[0]; const name = getNameOfDeclaration(declaration); if (name) { + if (name.kind === SyntaxKind.ComputedPropertyName && + symbol.flags & SymbolFlags.Transient && + !((symbol as TransientSymbol).checkFlags & CheckFlags.Late) && + !isWellKnownSymbolSyntactically((name as ComputedPropertyName).expression) && + symbol.escapedName) { + return "[\"" + unescapeLeadingUnderscores(symbol.escapedName) + "\"]"; + } return declarationNameToString(name); } if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { @@ -14611,7 +14618,7 @@ namespace ts { let propertiesTable = createSymbolTable(); let propertiesArray: Symbol[] = []; - let spread: Type = emptyObjectType; + let intermediate: Type = emptyObjectType; let propagatedFlags: TypeFlags = TypeFlags.FreshLiteral; const contextualType = getApparentTypeOfContextualType(node); @@ -14667,7 +14674,7 @@ namespace ts { typeFlags |= type.flags; if (isArray(literalName)) { hasUnionedComputedProperty = true; - next(createUnion(memberDecl, member, literalName, type)); + updateIntermediateType(getUnionFromLiteralUnion(memberDecl, member, literalName, type)); continue; } @@ -14678,14 +14685,14 @@ namespace ts { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - next(getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ false)); + updateIntermediateType(getSpreadType(intermediate, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ false)); } const type = checkExpression((memberDecl as SpreadAssignment).expression); if (!isValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } - spread = getSpreadType(spread, type, node.symbol, propagatedFlags, /*looseIndexes*/ false); + intermediate = getSpreadType(intermediate, type, node.symbol, propagatedFlags, /*looseIndexes*/ false); offset = i + 1; continue; } @@ -14717,7 +14724,7 @@ namespace ts { // type with those properties for which the binding pattern specifies a default value. if (contextualTypeHasPattern) { for (const prop of getPropertiesOfType(contextualType)) { - if (!propertiesTable.get(prop.escapedName) && !(spread && getPropertyOfType(spread, prop.escapedName))) { + if (!propertiesTable.get(prop.escapedName) && !(intermediate && getPropertyOfType(intermediate, prop.escapedName))) { if (!(prop.flags & SymbolFlags.Optional)) { error(prop.valueDeclaration || (prop).bindingElement, Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); @@ -14728,13 +14735,11 @@ namespace ts { } } - if (spread !== emptyObjectType) { + if (intermediate !== emptyObjectType) { if (propertiesArray.length > 0) { - // TODO: This is now insufficient; sometimes the spread is a result of a computed property with type union of literal type - // getSpreadType will *sometimes* work here, but not always - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ hasUnionedComputedProperty); + intermediate = getSpreadType(intermediate, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ hasUnionedComputedProperty); } - return spread; + return intermediate; } return createObjectLiteralType(); @@ -14746,24 +14751,34 @@ namespace ts { return escapeLeadingUnderscores("" + (type as LiteralType).value); } - function next(type: Type) { - spread = type; + function updateIntermediateType(type: Type) { + intermediate = type; propertiesArray = []; propertiesTable = createSymbolTable(); } - function createUnion(memberDecl: ObjectLiteralElementLike, member: Symbol, literalNames: __String[], type: Type) { + function getUnionFromLiteralUnion(memberDecl: ObjectLiteralElementLike, member: Symbol, literalNames: __String[], type: Type) { const types: Type[] = []; for (const literalName of literalNames) { const prop = createProperty(memberDecl, member, literalName, type); propertiesArray.push(prop); + let duplicate: Symbol; + if (propertiesTable.has(prop.escapedName)) { + duplicate = propertiesTable.get(prop.escapedName); + } propertiesTable.set(prop.escapedName, prop); + types.push(createObjectLiteralType()); + propertiesArray.pop(); - propertiesTable.delete(prop.escapedName); // Probably fine?? + if (duplicate) { + propertiesTable.set(prop.escapedName, duplicate); + } + else { + propertiesTable.delete(prop.escapedName); + } } - // TODO: Spread maybe isn't right, because it's so weird - return getSpreadType(spread, getUnionType(types), node.symbol, propagatedFlags, /*looseIndexes*/ true); + return getSpreadType(intermediate, getUnionType(types), node.symbol, propagatedFlags, /*looseIndexes*/ true); } // TODO: Probably don't need the second parameter From 3123bef74881a4daf82e746917769624bdbd6b5b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 5 Jan 2018 16:22:39 -0800 Subject: [PATCH 04/14] Clean up variable naming --- src/compiler/checker.ts | 135 ++++++++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 45 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b87cc632d4bbc..3bb55ba410ee6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4303,22 +4303,39 @@ namespace ts { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) const name = declaration.propertyName || declaration.name; if (isComputedNonLiteralName(name)) { - // computed properties with non-literal names are treated as 'any' - return anyType; + const computedType = checkComputedPropertyName(name); + if (!computedType) { + return anyType; + } + else if (computedType.flags & TypeFlags.Literal) { + const text = getTextOfPropertyLiteralType(computedType); + const declaredType = getTypeOfPropertyOfType(parentType, text); + type = declaredType && getFlowTypeOfReference(declaration, declaredType) || + computedType.flags & TypeFlags.NumberLiteral && getIndexTypeOfType(parentType, IndexKind.Number) || + getIndexTypeOfType(parentType, IndexKind.String); + } + else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { + type = (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(parentType, IndexKind.Number) || + getIndexTypeOfType(parentType, IndexKind.String); + } + else { + return anyType; + } } + else { + // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, + // or otherwise the type of the string index signature. + const text = getTextOfPropertyName(name); - // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, - // or otherwise the type of the string index signature. - const text = getTextOfPropertyName(name); - - // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation - if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) { - parentType = getNonNullableType(parentType); + // Relax null check on ambient destructuring parameters, since the parameters have no implementation and are just documentation + if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) { + parentType = getNonNullableType(parentType); + } + const declaredType = getTypeOfPropertyOfType(parentType, text); + type = declaredType && getFlowTypeOfReference(declaration, declaredType) || + isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) || + getIndexTypeOfType(parentType, IndexKind.String); } - const declaredType = getTypeOfPropertyOfType(parentType, text); - type = declaredType && getFlowTypeOfReference(declaration, declaredType) || - isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) || - getIndexTypeOfType(parentType, IndexKind.String); if (!type) { error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name)); return unknownType; @@ -4547,17 +4564,23 @@ namespace ts { let hasComputedProperties = false; forEach(pattern.elements, e => { const name = e.propertyName || e.name; - if (isComputedNonLiteralName(name)) { - // do not include computed properties in the implied type - hasComputedProperties = true; - return; - } + let text: __String; if (e.dotDotDotToken) { stringIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false); return; } - - const text = getTextOfPropertyName(name); + if (isComputedNonLiteralName(name)) { + // only include computed properties with literal types in the implied type + const computedType = checkComputedPropertyName(name); + if (!computedType || !(computedType.flags & TypeFlags.Literal)) { + hasComputedProperties = true; + return; + } + text = getTextOfPropertyLiteralType(computedType); + } + else { + text = getTextOfPropertyName(name); + } const flags = SymbolFlags.Property | (e.initializer ? SymbolFlags.Optional : 0); const symbol = createSymbol(flags, text); symbol.type = getTypeFromBindingElement(e, includePatternInType, reportErrors); @@ -14648,12 +14671,12 @@ namespace ts { let type: Type; if (memberDecl.kind === SyntaxKind.PropertyAssignment) { if (memberDecl.name.kind === SyntaxKind.ComputedPropertyName) { - const t = checkComputedPropertyName(memberDecl.name); - if (t.flags & TypeFlags.Literal) { - literalName = getLiteralPropertyName(t); + const computedType = checkComputedPropertyName(memberDecl.name); + if (computedType.flags & TypeFlags.Literal) { + literalName = getTextOfPropertyLiteralType(computedType); } - else if (t.flags & TypeFlags.Union && (t as UnionType).types.every(t2 => !!(t2.flags & TypeFlags.Literal))) { - literalName = (t as UnionType).types.map(getLiteralPropertyName); + else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { + literalName = (computedType as UnionType).types.map(getTextOfPropertyLiteralType); } } type = checkPropertyAssignment(memberDecl, checkMode); @@ -14744,13 +14767,6 @@ namespace ts { return createObjectLiteralType(); - function getLiteralPropertyName(type: Type): __String { - if (type.flags & TypeFlags.Intrinsic) { - return (type as IntrinsicType).intrinsicName as __String; - } - return escapeLeadingUnderscores("" + (type as LiteralType).value); - } - function updateIntermediateType(type: Type) { intermediate = type; propertiesArray = []; @@ -14841,6 +14857,13 @@ namespace ts { } } + function getTextOfPropertyLiteralType(type: Type): __String { + if (type.flags & TypeFlags.Intrinsic) { + return (type as IntrinsicType).intrinsicName as __String; + } + return escapeLeadingUnderscores("" + (type as LiteralType).value); + } + function isValidSpreadType(type: Type): boolean { return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive) || getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) || @@ -18636,19 +18659,38 @@ namespace ts { function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: ReadonlyArray) { if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { const name = (property).name; - if (name.kind === SyntaxKind.ComputedPropertyName) { - checkComputedPropertyName(name); - } + const computedType = name.kind === SyntaxKind.ComputedPropertyName ? checkComputedPropertyName(name) : undefined; + let type: Type; if (isComputedNonLiteralName(name)) { - return undefined; + if (!computedType) { + return undefined; + } + else if (computedType.flags & TypeFlags.Literal) { + const text = getTextOfPropertyLiteralType(computedType); + type = isTypeAny(objectLiteralType) + ? objectLiteralType + : getTypeOfPropertyOfType(objectLiteralType, text) || + computedType.flags & TypeFlags.NumberLiteral && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || + getIndexTypeOfType(objectLiteralType, IndexKind.String); + } + else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { + type = isTypeAny(objectLiteralType) + ? objectLiteralType + : (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || + getIndexTypeOfType(objectLiteralType, IndexKind.String); + } + else { + return undefined; + } + } + else { + const text = getTextOfPropertyName(name); + type = isTypeAny(objectLiteralType) + ? objectLiteralType + : getTypeOfPropertyOfType(objectLiteralType, text) || + isNumericLiteralName(text) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || + getIndexTypeOfType(objectLiteralType, IndexKind.String); } - - const text = getTextOfPropertyName(name); - const type = isTypeAny(objectLiteralType) - ? objectLiteralType - : getTypeOfPropertyOfType(objectLiteralType, text) || - isNumericLiteralName(text) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || - getIndexTypeOfType(objectLiteralType, IndexKind.String); if (type) { if (property.kind === SyntaxKind.ShorthandPropertyAssignment) { return checkDestructuringAssignment(property, type); @@ -24662,8 +24704,11 @@ namespace ts { // [{ property1: p1, property2 }] = elems; const typeOfArrayLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(expr.parent); const elementType = checkIteratedTypeOrElementType(typeOfArrayLiteral || unknownType, expr.parent, /*allowStringInput*/ false, /*allowAsyncIterables*/ false) || unknownType; - return checkArrayLiteralDestructuringElementAssignment(expr.parent, typeOfArrayLiteral, - indexOf((expr.parent).elements, expr), elementType || unknownType); + return checkArrayLiteralDestructuringElementAssignment( + expr.parent, + typeOfArrayLiteral, + indexOf((expr.parent).elements, expr), + elementType || unknownType); } // Gets the property symbol corresponding to the property in destructuring assignment From 6bec7533a34c742ee8ab7b81e7df17b4110ac127 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 5 Jan 2018 16:23:20 -0800 Subject: [PATCH 05/14] More computed property cases + Update baselines --- .../computedPropertyNames10_ES5.types | 4 +- .../computedPropertyNames10_ES6.types | 4 +- .../computedPropertyNames46_ES5.types | 4 +- .../computedPropertyNames46_ES6.types | 4 +- .../computedPropertyNames47_ES5.types | 4 +- .../computedPropertyNames47_ES6.types | 4 +- .../computedPropertyNames48_ES5.types | 2 +- .../computedPropertyNames48_ES6.types | 2 +- .../computedPropertyNames4_ES5.types | 4 +- .../computedPropertyNames4_ES6.types | 4 +- .../computedPropertyNames5_ES5.types | 4 +- .../computedPropertyNames5_ES6.types | 4 +- .../computedPropertyNames9_ES5.types | 4 +- .../computedPropertyNames9_ES6.types | 4 +- ...edPropertyUnionLiftsToUnionType.errors.txt | 62 ++++++ .../computedPropertyUnionLiftsToUnionType.js | 102 ++++++--- ...putedPropertyUnionLiftsToUnionType.symbols | 189 +++++++++++++--- ...omputedPropertyUnionLiftsToUnionType.types | 205 ++++++++++++++++-- ...puterPropertiesInES5ShouldBeTransformed.js | 3 +- ...erPropertiesInES5ShouldBeTransformed.types | 4 +- .../reference/exportDefaultParenthesize.types | 2 +- .../literalsInComputedProperties1.symbols | 2 +- .../literalsInComputedProperties1.types | 12 +- .../objectLiteralEnumPropertyNames.types | 2 +- tests/baselines/reference/objectSpread.types | 6 +- .../parserComputedPropertyName35.types | 4 +- .../parserComputedPropertyName41.types | 4 +- ...puterPropertiesInES5ShouldBeTransformed.ts | 2 +- .../computedPropertyUnionLiftsToUnionType.ts | 57 +++-- 29 files changed, 570 insertions(+), 138 deletions(-) create mode 100644 tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt diff --git a/tests/baselines/reference/computedPropertyNames10_ES5.types b/tests/baselines/reference/computedPropertyNames10_ES5.types index 4750d44fde8b2..f76476e4e55da 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES5.types +++ b/tests/baselines/reference/computedPropertyNames10_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } ->{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } +>v : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } +>{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } [s]() { }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames10_ES6.types b/tests/baselines/reference/computedPropertyNames10_ES6.types index 3a12047f588fe..b294517022c92 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES6.types +++ b/tests/baselines/reference/computedPropertyNames10_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } ->{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } +>v : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } +>{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } [s]() { }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames46_ES5.types b/tests/baselines/reference/computedPropertyNames46_ES5.types index e90d1a6c49864..d57d03ee79b5a 100644 --- a/tests/baselines/reference/computedPropertyNames46_ES5.types +++ b/tests/baselines/reference/computedPropertyNames46_ES5.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNames46_ES5.ts === var o = { ->o : { ["" || 0]: number; } ->{ ["" || 0]: 0} : { ["" || 0]: number; } +>o : { ["0"]: number; } +>{ ["" || 0]: 0} : { ["0"]: number; } ["" || 0]: 0 >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames46_ES6.types b/tests/baselines/reference/computedPropertyNames46_ES6.types index 34aac7489c9dc..ef3ae6eef845e 100644 --- a/tests/baselines/reference/computedPropertyNames46_ES6.types +++ b/tests/baselines/reference/computedPropertyNames46_ES6.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNames46_ES6.ts === var o = { ->o : { ["" || 0]: number; } ->{ ["" || 0]: 0} : { ["" || 0]: number; } +>o : { ["0"]: number; } +>{ ["" || 0]: 0} : { ["0"]: number; } ["" || 0]: 0 >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames47_ES5.types b/tests/baselines/reference/computedPropertyNames47_ES5.types index 9c01db098467c..0b0e4580d7f46 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES5.types +++ b/tests/baselines/reference/computedPropertyNames47_ES5.types @@ -8,8 +8,8 @@ enum E2 { x } >x : E2 var o = { ->o : { [E1.x || E2.x]: number; } ->{ [E1.x || E2.x]: 0} : { [E1.x || E2.x]: number; } +>o : { ["0"]: number; } +>{ [E1.x || E2.x]: 0} : { ["0"]: number; } [E1.x || E2.x]: 0 >E1.x || E2.x : E2 diff --git a/tests/baselines/reference/computedPropertyNames47_ES6.types b/tests/baselines/reference/computedPropertyNames47_ES6.types index c2e65523e465b..bd594bb56c285 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES6.types +++ b/tests/baselines/reference/computedPropertyNames47_ES6.types @@ -8,8 +8,8 @@ enum E2 { x } >x : E2 var o = { ->o : { [E1.x || E2.x]: number; } ->{ [E1.x || E2.x]: 0} : { [E1.x || E2.x]: number; } +>o : { ["0"]: number; } +>{ [E1.x || E2.x]: 0} : { ["0"]: number; } [E1.x || E2.x]: 0 >E1.x || E2.x : E2 diff --git a/tests/baselines/reference/computedPropertyNames48_ES5.types b/tests/baselines/reference/computedPropertyNames48_ES5.types index 25818fff967dd..0e61fa9dfa2d3 100644 --- a/tests/baselines/reference/computedPropertyNames48_ES5.types +++ b/tests/baselines/reference/computedPropertyNames48_ES5.types @@ -41,7 +41,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ ["" || 0]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ ["" || 0]: ""} : { ["" || 0]: string; } +>{ ["" || 0]: ""} : { ["0"]: string; } ["" || 0]: "" >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames48_ES6.types b/tests/baselines/reference/computedPropertyNames48_ES6.types index 65f93239f30a9..d29494a430084 100644 --- a/tests/baselines/reference/computedPropertyNames48_ES6.types +++ b/tests/baselines/reference/computedPropertyNames48_ES6.types @@ -41,7 +41,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ ["" || 0]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ ["" || 0]: ""} : { ["" || 0]: string; } +>{ ["" || 0]: ""} : { ["0"]: string; } ["" || 0]: "" >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames4_ES5.types b/tests/baselines/reference/computedPropertyNames4_ES5.types index f0e105be4a72b..83cdf869bc580 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES5.types +++ b/tests/baselines/reference/computedPropertyNames4_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } +>v : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyNames4_ES6.types b/tests/baselines/reference/computedPropertyNames4_ES6.types index 178eca88a72c7..35a160bd86a80 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES6.types +++ b/tests/baselines/reference/computedPropertyNames4_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; [`hello bye`]: number; } +>v : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyNames5_ES5.types b/tests/baselines/reference/computedPropertyNames5_ES5.types index 027bfd2acb040..f47c9383a901f 100644 --- a/tests/baselines/reference/computedPropertyNames5_ES5.types +++ b/tests/baselines/reference/computedPropertyNames5_ES5.types @@ -3,8 +3,8 @@ var b: boolean; >b : boolean var v = { ->v : { [x: string]: number; [x: number]: any; [true]: number; } | { [x: string]: number; [x: number]: any; [true]: number; [b]: number; } ->{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; [true]: number; } | { [x: string]: number; [x: number]: null; [true]: number; [b]: number; } +>v : { [x: string]: number; [x: number]: any; ["true"]: number; } | { [x: string]: number; [x: number]: any; ["true"]: number; ["false"]: number; } +>{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; ["true"]: number; } | { [x: string]: number; [x: number]: null; ["true"]: number; ["false"]: number; } [b]: 0, >b : boolean diff --git a/tests/baselines/reference/computedPropertyNames5_ES6.types b/tests/baselines/reference/computedPropertyNames5_ES6.types index c160d3d44e8ac..be0b018e91e82 100644 --- a/tests/baselines/reference/computedPropertyNames5_ES6.types +++ b/tests/baselines/reference/computedPropertyNames5_ES6.types @@ -3,8 +3,8 @@ var b: boolean; >b : boolean var v = { ->v : { [x: string]: number; [x: number]: any; [true]: number; } | { [x: string]: number; [x: number]: any; [true]: number; [b]: number; } ->{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; [true]: number; } | { [x: string]: number; [x: number]: null; [true]: number; [b]: number; } +>v : { [x: string]: number; [x: number]: any; ["true"]: number; } | { [x: string]: number; [x: number]: any; ["true"]: number; ["false"]: number; } +>{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; ["true"]: number; } | { [x: string]: number; [x: number]: null; ["true"]: number; ["false"]: number; } [b]: 0, >b : boolean diff --git a/tests/baselines/reference/computedPropertyNames9_ES5.types b/tests/baselines/reference/computedPropertyNames9_ES5.types index 114aa4ef8128f..221f73e5ab899 100644 --- a/tests/baselines/reference/computedPropertyNames9_ES5.types +++ b/tests/baselines/reference/computedPropertyNames9_ES5.types @@ -19,8 +19,8 @@ function f(x): any { } >x : any var v = { ->v : { [x: string]: number; [x: number]: number; [f(true)]: number; } ->{ [f("")]: 0, [f(0)]: 0, [f(true)]: 0} : { [x: string]: number; [x: number]: number; [f(true)]: number; } +>v : { [x: string]: number; [x: number]: number; ["true"]: number; } +>{ [f("")]: 0, [f(0)]: 0, [f(true)]: 0} : { [x: string]: number; [x: number]: number; ["true"]: number; } [f("")]: 0, >f("") : string diff --git a/tests/baselines/reference/computedPropertyNames9_ES6.types b/tests/baselines/reference/computedPropertyNames9_ES6.types index d37505d863064..7830dc30fb74e 100644 --- a/tests/baselines/reference/computedPropertyNames9_ES6.types +++ b/tests/baselines/reference/computedPropertyNames9_ES6.types @@ -19,8 +19,8 @@ function f(x): any { } >x : any var v = { ->v : { [x: string]: number; [x: number]: number; [f(true)]: number; } ->{ [f("")]: 0, [f(0)]: 0, [f(true)]: 0} : { [x: string]: number; [x: number]: number; [f(true)]: number; } +>v : { [x: string]: number; [x: number]: number; ["true"]: number; } +>{ [f("")]: 0, [f(0)]: 0, [f(true)]: 0} : { [x: string]: number; [x: number]: number; ["true"]: number; } [f("")]: 0, >f("") : string diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt new file mode 100644 index 0000000000000..f5869070e2090 --- /dev/null +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt @@ -0,0 +1,62 @@ +tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(32,4): error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. +tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(40,7): error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. + + +==== tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts (2 errors) ==== + declare var ab: 'a' | 'b'; + declare var cd: 'c' | 'd'; + declare var onetwo: 1 | 2; + enum Alphabet { + Aleph, + Bet, + } + declare var alphabet: Alphabet; + + const x: { a: string } | { b: string } = { [ab]: 'hi' } + // multiple unions + const y: { a: string, m: number, c: string } + | { a: string, m: number, d: string } + | { b: string, m: number, c: string } + | { b: string, m: number, d: string } = { [ab]: 'hi', m: 1, [cd]: 'there' } + // union, spread (with union inside), union + const s: { a: string, c: string } | { b: string, c: string } = { [ab]: 'hi', ...{ c: 'no' }} + const sd: { a: string } | { b: string } = { [ab]: 'hi', ...{ a: 'no' }} + const sn: { a: string, c: string } + | { a: string, d: string } + | { b: string, c: string } + | { b: string, d: string } = { [ab]: 'hi', ...{ [cd]: 'no' }} + // methods + const m: { a: string, m(): number, p: number } | { b: string, m(): number, p: number } = + { [ab]: 'hi', m() { return 1 }, get p() { return 2 } } + // other literal types: number, enum (string and number) + const n: { "1": string } | { "2": string } = { [onetwo]: 'hi' } + const e: { "0": string } | { "1": string } = { [alphabet]: 'hi' } + + // destructuring + declare let u: { a: string } | { b: string } + ({ [ab]: du } = u) // implicit any error + ~~~~ +!!! error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. + var du: any + declare let sig: { [s: string]: string } + ({ [ab]: ds } = sig) // fine, comes from index signature + var ds: string + + var duo: any + var dso: string + var { [ab]: duo } = u // implicit any error (or similar to the singleton one) + ~~~~ +!!! error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. + var { [ab]: dso } = sig // fine + + // number index signatures + declare let sin: { [n: number]: number } + var dn: number + ({ [onetwo]: dn } = sin) // fine, from index signature + var dno: number + var { [onetwo]: dno } = sin // fine, from index signature + + + + + \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js index 762391d301c44..969e10599802f 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js @@ -1,45 +1,85 @@ //// [computedPropertyUnionLiftsToUnionType.ts] declare var ab: 'a' | 'b'; declare var cd: 'c' | 'd'; -// More cases: -// add spreads -// other literal types: number, boolean, enum (string and number) +declare var onetwo: 1 | 2; +enum Alphabet { + Aleph, + Bet, +} +declare var alphabet: Alphabet; + +const x: { a: string } | { b: string } = { [ab]: 'hi' } // multiple unions +const y: { a: string, m: number, c: string } + | { a: string, m: number, d: string } + | { b: string, m: number, c: string } + | { b: string, m: number, d: string } = { [ab]: 'hi', m: 1, [cd]: 'there' } // union, spread (with union inside), union -// methods and other stuff that would get mangled by spread (since I use spread internally) -const x: { a: string } | { b: string } = { [ab]: 'hi' } -const y: { a: string, c: string } | { a: string, d: string } | { b: string, c: string } | { b: string, d: string } = - { [ab]: 'hi', [cd]: 'there' } +const s: { a: string, c: string } | { b: string, c: string } = { [ab]: 'hi', ...{ c: 'no' }} +const sd: { a: string } | { b: string } = { [ab]: 'hi', ...{ a: 'no' }} +const sn: { a: string, c: string } + | { a: string, d: string } + | { b: string, c: string } + | { b: string, d: string } = { [ab]: 'hi', ...{ [cd]: 'no' }} +// methods +const m: { a: string, m(): number, p: number } | { b: string, m(): number, p: number } = + { [ab]: 'hi', m() { return 1 }, get p() { return 2 } } +// other literal types: number, enum (string and number) +const n: { "1": string } | { "2": string } = { [onetwo]: 'hi' } +const e: { "0": string } | { "1": string } = { [alphabet]: 'hi' } -// in destructuring???!! -/* -declare let o: { [t]: string } +// destructuring declare let u: { a: string } | { b: string } -const { [t]: doo } = o -const { [t]: duo } = u -var t: 'a' | 'b' = doo -var t: 'a' | 'b' = duo -*/ +({ [ab]: du } = u) // implicit any error +var du: any +declare let sig: { [s: string]: string } +({ [ab]: ds } = sig) // fine, comes from index signature +var ds: string + +var duo: any +var dso: string +var { [ab]: duo } = u // implicit any error (or similar to the singleton one) +var { [ab]: dso } = sig // fine + +// number index signatures +declare let sin: { [n: number]: number } +var dn: number +({ [onetwo]: dn } = sin) // fine, from index signature +var dno: number +var { [onetwo]: dno } = sin // fine, from index signature + + //// [computedPropertyUnionLiftsToUnionType.js] -// More cases: -// add spreads -// other literal types: number, boolean, enum (string and number) +var Alphabet; +(function (Alphabet) { + Alphabet[Alphabet["Aleph"] = 0] = "Aleph"; + Alphabet[Alphabet["Bet"] = 1] = "Bet"; +})(Alphabet || (Alphabet = {})); +const x = { [ab]: 'hi' }; // multiple unions +const y = { [ab]: 'hi', m: 1, [cd]: 'there' }; // union, spread (with union inside), union -// methods and other stuff that would get mangled by spread (since I use spread internally) -var x = (_a = {}, _a[ab] = 'hi', _a); -var y = (_b = {}, _b[ab] = 'hi', _b[cd] = 'there', _b); -var _a, _b; -// in destructuring???!! -/* -declare let o: { [t]: string } -declare let u: { a: string } | { b: string } -const { [t]: doo } = o -const { [t]: duo } = u -var t: 'a' | 'b' = doo -var t: 'a' | 'b' = duo -*/ +const s = Object.assign({ [ab]: 'hi' }, { c: 'no' }); +const sd = Object.assign({ [ab]: 'hi' }, { a: 'no' }); +const sn = Object.assign({ [ab]: 'hi' }, { [cd]: 'no' }); +// methods +const m = { [ab]: 'hi', m() { return 1; }, get p() { return 2; } }; +// other literal types: number, enum (string and number) +const n = { [onetwo]: 'hi' }; +const e = { [alphabet]: 'hi' }; +({ [ab]: du } = u); // implicit any error +var du; +({ [ab]: ds } = sig); // fine, comes from index signature +var ds; +var duo; +var dso; +var { [ab]: duo } = u; // implicit any error (or similar to the singleton one) +var { [ab]: dso } = sig; // fine +var dn; +({ [onetwo]: dn } = sin); // fine, from index signature +var dno; +var { [onetwo]: dno } = sin; // fine, from index signature diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols index 9dd217d6da13b..ae4eab628e0a8 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols @@ -5,42 +5,177 @@ declare var ab: 'a' | 'b'; declare var cd: 'c' | 'd'; >cd : Symbol(cd, Decl(computedPropertyUnionLiftsToUnionType.ts, 1, 11)) -// More cases: -// add spreads -// other literal types: number, boolean, enum (string and number) +declare var onetwo: 1 | 2; +>onetwo : Symbol(onetwo, Decl(computedPropertyUnionLiftsToUnionType.ts, 2, 11)) + +enum Alphabet { +>Alphabet : Symbol(Alphabet, Decl(computedPropertyUnionLiftsToUnionType.ts, 2, 26)) + + Aleph, +>Aleph : Symbol(Alphabet.Aleph, Decl(computedPropertyUnionLiftsToUnionType.ts, 3, 15)) + + Bet, +>Bet : Symbol(Alphabet.Bet, Decl(computedPropertyUnionLiftsToUnionType.ts, 4, 10)) +} +declare var alphabet: Alphabet; +>alphabet : Symbol(alphabet, Decl(computedPropertyUnionLiftsToUnionType.ts, 7, 11)) +>Alphabet : Symbol(Alphabet, Decl(computedPropertyUnionLiftsToUnionType.ts, 2, 26)) + +const x: { a: string } | { b: string } = { [ab]: 'hi' } +>x : Symbol(x, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 10)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 26)) +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) + // multiple unions +const y: { a: string, m: number, c: string } +>y : Symbol(y, Decl(computedPropertyUnionLiftsToUnionType.ts, 11, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 11, 10)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 11, 21)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 11, 32)) + + | { a: string, m: number, d: string } +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 12, 7)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 12, 18)) +>d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 12, 29)) + + | { b: string, m: number, c: string } +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 13, 7)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 13, 18)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 13, 29)) + + | { b: string, m: number, d: string } = { [ab]: 'hi', m: 1, [cd]: 'there' } +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 14, 7)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 14, 18)) +>d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 14, 29)) +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 14, 57)) +>cd : Symbol(cd, Decl(computedPropertyUnionLiftsToUnionType.ts, 1, 11)) + // union, spread (with union inside), union -// methods and other stuff that would get mangled by spread (since I use spread internally) -const x: { a: string } | { b: string } = { [ab]: 'hi' } ->x : Symbol(x, Decl(computedPropertyUnionLiftsToUnionType.ts, 8, 5)) ->a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 8, 10)) ->b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 8, 26)) +const s: { a: string, c: string } | { b: string, c: string } = { [ab]: 'hi', ...{ c: 'no' }} +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 16, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 16, 10)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 16, 21)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 16, 37)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 16, 48)) >ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 16, 81)) -const y: { a: string, c: string } | { a: string, d: string } | { b: string, c: string } | { b: string, d: string } = ->y : Symbol(y, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 5)) ->a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 10)) ->c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 21)) ->a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 37)) ->d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 48)) ->b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 64)) ->c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 75)) ->b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 91)) ->d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 9, 102)) +const sd: { a: string } | { b: string } = { [ab]: 'hi', ...{ a: 'no' }} +>sd : Symbol(sd, Decl(computedPropertyUnionLiftsToUnionType.ts, 17, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 17, 11)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 17, 27)) +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 17, 60)) + +const sn: { a: string, c: string } +>sn : Symbol(sn, Decl(computedPropertyUnionLiftsToUnionType.ts, 18, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 18, 11)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 18, 22)) - { [ab]: 'hi', [cd]: 'there' } + | { a: string, d: string } +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 19, 7)) +>d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 19, 18)) + + | { b: string, c: string } +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 20, 7)) +>c : Symbol(c, Decl(computedPropertyUnionLiftsToUnionType.ts, 20, 18)) + + | { b: string, d: string } = { [ab]: 'hi', ...{ [cd]: 'no' }} +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 21, 7)) +>d : Symbol(d, Decl(computedPropertyUnionLiftsToUnionType.ts, 21, 18)) >ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) >cd : Symbol(cd, Decl(computedPropertyUnionLiftsToUnionType.ts, 1, 11)) -// in destructuring???!! -/* -declare let o: { [t]: string } +// methods +const m: { a: string, m(): number, p: number } | { b: string, m(): number, p: number } = +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 23, 5)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 23, 10)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 23, 21)) +>p : Symbol(p, Decl(computedPropertyUnionLiftsToUnionType.ts, 23, 34)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 23, 50)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 23, 61)) +>p : Symbol(p, Decl(computedPropertyUnionLiftsToUnionType.ts, 23, 74)) + + { [ab]: 'hi', m() { return 1 }, get p() { return 2 } } +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>m : Symbol(m, Decl(computedPropertyUnionLiftsToUnionType.ts, 24, 17)) +>p : Symbol(p, Decl(computedPropertyUnionLiftsToUnionType.ts, 24, 35)) + +// other literal types: number, enum (string and number) +const n: { "1": string } | { "2": string } = { [onetwo]: 'hi' } +>n : Symbol(n, Decl(computedPropertyUnionLiftsToUnionType.ts, 26, 5)) +>onetwo : Symbol(onetwo, Decl(computedPropertyUnionLiftsToUnionType.ts, 2, 11)) + +const e: { "0": string } | { "1": string } = { [alphabet]: 'hi' } +>e : Symbol(e, Decl(computedPropertyUnionLiftsToUnionType.ts, 27, 5)) +>alphabet : Symbol(alphabet, Decl(computedPropertyUnionLiftsToUnionType.ts, 7, 11)) + +// destructuring declare let u: { a: string } | { b: string } -const { [t]: doo } = o -const { [t]: duo } = u -var t: 'a' | 'b' = doo -var t: 'a' | 'b' = duo -*/ +>u : Symbol(u, Decl(computedPropertyUnionLiftsToUnionType.ts, 30, 11)) +>a : Symbol(a, Decl(computedPropertyUnionLiftsToUnionType.ts, 30, 16)) +>b : Symbol(b, Decl(computedPropertyUnionLiftsToUnionType.ts, 30, 32)) + +({ [ab]: du } = u) // implicit any error +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>du : Symbol(du, Decl(computedPropertyUnionLiftsToUnionType.ts, 32, 3)) +>u : Symbol(u, Decl(computedPropertyUnionLiftsToUnionType.ts, 30, 11)) + +var du: any +>du : Symbol(du, Decl(computedPropertyUnionLiftsToUnionType.ts, 32, 3)) + +declare let sig: { [s: string]: string } +>sig : Symbol(sig, Decl(computedPropertyUnionLiftsToUnionType.ts, 33, 11)) +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 33, 20)) + +({ [ab]: ds } = sig) // fine, comes from index signature +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>ds : Symbol(ds, Decl(computedPropertyUnionLiftsToUnionType.ts, 35, 3)) +>sig : Symbol(sig, Decl(computedPropertyUnionLiftsToUnionType.ts, 33, 11)) + +var ds: string +>ds : Symbol(ds, Decl(computedPropertyUnionLiftsToUnionType.ts, 35, 3)) + +var duo: any +>duo : Symbol(duo, Decl(computedPropertyUnionLiftsToUnionType.ts, 37, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 39, 5)) + +var dso: string +>dso : Symbol(dso, Decl(computedPropertyUnionLiftsToUnionType.ts, 38, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 40, 5)) + +var { [ab]: duo } = u // implicit any error (or similar to the singleton one) +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>duo : Symbol(duo, Decl(computedPropertyUnionLiftsToUnionType.ts, 37, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 39, 5)) +>u : Symbol(u, Decl(computedPropertyUnionLiftsToUnionType.ts, 30, 11)) + +var { [ab]: dso } = sig // fine +>ab : Symbol(ab, Decl(computedPropertyUnionLiftsToUnionType.ts, 0, 11)) +>dso : Symbol(dso, Decl(computedPropertyUnionLiftsToUnionType.ts, 38, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 40, 5)) +>sig : Symbol(sig, Decl(computedPropertyUnionLiftsToUnionType.ts, 33, 11)) + +// number index signatures +declare let sin: { [n: number]: number } +>sin : Symbol(sin, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 11)) +>n : Symbol(n, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 20)) + +var dn: number +>dn : Symbol(dn, Decl(computedPropertyUnionLiftsToUnionType.ts, 44, 3)) + +({ [onetwo]: dn } = sin) // fine, from index signature +>onetwo : Symbol(onetwo, Decl(computedPropertyUnionLiftsToUnionType.ts, 2, 11)) +>dn : Symbol(dn, Decl(computedPropertyUnionLiftsToUnionType.ts, 44, 3)) +>sin : Symbol(sin, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 11)) + +var dno: number +>dno : Symbol(dno, Decl(computedPropertyUnionLiftsToUnionType.ts, 46, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 47, 5)) + +var { [onetwo]: dno } = sin // fine, from index signature +>onetwo : Symbol(onetwo, Decl(computedPropertyUnionLiftsToUnionType.ts, 2, 11)) +>dno : Symbol(dno, Decl(computedPropertyUnionLiftsToUnionType.ts, 46, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 47, 5)) +>sin : Symbol(sin, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 11)) + + diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types index 8143d159c3df2..9379d25eba7ee 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types @@ -5,47 +5,212 @@ declare var ab: 'a' | 'b'; declare var cd: 'c' | 'd'; >cd : "c" | "d" -// More cases: -// add spreads -// other literal types: number, boolean, enum (string and number) -// multiple unions -// union, spread (with union inside), union -// methods and other stuff that would get mangled by spread (since I use spread internally) +declare var onetwo: 1 | 2; +>onetwo : 2 | 1 + +enum Alphabet { +>Alphabet : Alphabet + + Aleph, +>Aleph : Alphabet.Aleph + + Bet, +>Bet : Alphabet.Bet +} +declare var alphabet: Alphabet; +>alphabet : Alphabet +>Alphabet : Alphabet + const x: { a: string } | { b: string } = { [ab]: 'hi' } >x : { a: string; } | { b: string; } >a : string >b : string ->{ [ab]: 'hi' } : { [ab]: string; } | { [ab]: string; } +>{ [ab]: 'hi' } : { ["a"]: string; } | { ["b"]: string; } >ab : "a" | "b" >'hi' : "hi" -const y: { a: string, c: string } | { a: string, d: string } | { b: string, c: string } | { b: string, d: string } = ->y : { a: string; c: string; } | { a: string; d: string; } | { b: string; c: string; } | { b: string; d: string; } +// multiple unions +const y: { a: string, m: number, c: string } +>y : { a: string; m: number; c: string; } | { a: string; m: number; d: string; } | { b: string; m: number; c: string; } | { b: string; m: number; d: string; } >a : string +>m : number >c : string + + | { a: string, m: number, d: string } >a : string +>m : number >d : string + + | { b: string, m: number, c: string } >b : string +>m : number >c : string + + | { b: string, m: number, d: string } = { [ab]: 'hi', m: 1, [cd]: 'there' } >b : string +>m : number >d : string - - { [ab]: 'hi', [cd]: 'there' } ->{ [ab]: 'hi', [cd]: 'there' } : { [cd]: string; [ab]: string; } | { [cd]: string; [ab]: string; } | { [cd]: string; [ab]: string; } | { [cd]: string; [ab]: string; } +>{ [ab]: 'hi', m: 1, [cd]: 'there' } : { m: number; ["c"]: string; ["a"]: string; } | { m: number; ["d"]: string; ["a"]: string; } | { m: number; ["c"]: string; ["b"]: string; } | { m: number; ["d"]: string; ["b"]: string; } >ab : "a" | "b" >'hi' : "hi" +>m : number +>1 : 1 >cd : "c" | "d" >'there' : "there" -// in destructuring???!! -/* -declare let o: { [t]: string } +// union, spread (with union inside), union +const s: { a: string, c: string } | { b: string, c: string } = { [ab]: 'hi', ...{ c: 'no' }} +>s : { a: string; c: string; } | { b: string; c: string; } +>a : string +>c : string +>b : string +>c : string +>{ [ab]: 'hi', ...{ c: 'no' }} : { c: string; ["a"]: string; } | { c: string; ["b"]: string; } +>ab : "a" | "b" +>'hi' : "hi" +>{ c: 'no' } : { c: string; } +>c : string +>'no' : "no" + +const sd: { a: string } | { b: string } = { [ab]: 'hi', ...{ a: 'no' }} +>sd : { a: string; } | { b: string; } +>a : string +>b : string +>{ [ab]: 'hi', ...{ a: 'no' }} : { a: string; } | { a: string; ["b"]: string; } +>ab : "a" | "b" +>'hi' : "hi" +>{ a: 'no' } : { a: string; } +>a : string +>'no' : "no" + +const sn: { a: string, c: string } +>sn : { a: string; c: string; } | { a: string; d: string; } | { b: string; c: string; } | { b: string; d: string; } +>a : string +>c : string + + | { a: string, d: string } +>a : string +>d : string + + | { b: string, c: string } +>b : string +>c : string + + | { b: string, d: string } = { [ab]: 'hi', ...{ [cd]: 'no' }} +>b : string +>d : string +>{ [ab]: 'hi', ...{ [cd]: 'no' }} : { ["c"]: string; ["a"]: string; } | { ["d"]: string; ["a"]: string; } | { ["c"]: string; ["b"]: string; } | { ["d"]: string; ["b"]: string; } +>ab : "a" | "b" +>'hi' : "hi" +>{ [cd]: 'no' } : { ["c"]: string; } | { ["d"]: string; } +>cd : "c" | "d" +>'no' : "no" + +// methods +const m: { a: string, m(): number, p: number } | { b: string, m(): number, p: number } = +>m : { a: string; m(): number; p: number; } | { b: string; m(): number; p: number; } +>a : string +>m : () => number +>p : number +>b : string +>m : () => number +>p : number + + { [ab]: 'hi', m() { return 1 }, get p() { return 2 } } +>{ [ab]: 'hi', m() { return 1 }, get p() { return 2 } } : { m(): number; p: number; ["a"]: string; } | { m(): number; p: number; ["b"]: string; } +>ab : "a" | "b" +>'hi' : "hi" +>m : () => number +>1 : 1 +>p : number +>2 : 2 + +// other literal types: number, enum (string and number) +const n: { "1": string } | { "2": string } = { [onetwo]: 'hi' } +>n : { "1": string; } | { "2": string; } +>{ [onetwo]: 'hi' } : { ["2"]: string; } | { ["1"]: string; } +>onetwo : 2 | 1 +>'hi' : "hi" + +const e: { "0": string } | { "1": string } = { [alphabet]: 'hi' } +>e : { "0": string; } | { "1": string; } +>{ [alphabet]: 'hi' } : { ["0"]: string; } | { ["1"]: string; } +>alphabet : Alphabet +>'hi' : "hi" + +// destructuring declare let u: { a: string } | { b: string } -const { [t]: doo } = o -const { [t]: duo } = u -var t: 'a' | 'b' = doo -var t: 'a' | 'b' = duo -*/ +>u : { a: string; } | { b: string; } +>a : string +>b : string + +({ [ab]: du } = u) // implicit any error +>({ [ab]: du } = u) : { a: string; } | { b: string; } +>{ [ab]: du } = u : { a: string; } | { b: string; } +>{ [ab]: du } : { ["a"]: any; } | { ["b"]: any; } +>ab : "a" | "b" +>du : any +>u : { a: string; } | { b: string; } + +var du: any +>du : any + +declare let sig: { [s: string]: string } +>sig : { [s: string]: string; } +>s : string + +({ [ab]: ds } = sig) // fine, comes from index signature +>({ [ab]: ds } = sig) : { [s: string]: string; } +>{ [ab]: ds } = sig : { [s: string]: string; } +>{ [ab]: ds } : { ["a"]: string; } | { ["b"]: string; } +>ab : "a" | "b" +>ds : string +>sig : { [s: string]: string; } + +var ds: string +>ds : string + +var duo: any +>duo : any + +var dso: string +>dso : string + +var { [ab]: duo } = u // implicit any error (or similar to the singleton one) +>ab : "a" | "b" +>duo : any +>u : { a: string; } | { b: string; } + +var { [ab]: dso } = sig // fine +>ab : "a" | "b" +>dso : string +>sig : { [s: string]: string; } + +// number index signatures +declare let sin: { [n: number]: number } +>sin : { [n: number]: number; } +>n : number + +var dn: number +>dn : number + +({ [onetwo]: dn } = sin) // fine, from index signature +>({ [onetwo]: dn } = sin) : { [n: number]: number; } +>{ [onetwo]: dn } = sin : { [n: number]: number; } +>{ [onetwo]: dn } : { ["2"]: number; } | { ["1"]: number; } +>onetwo : 2 | 1 +>dn : number +>sin : { [n: number]: number; } + +var dno: number +>dno : number + +var { [onetwo]: dno } = sin // fine, from index signature +>onetwo : 2 | 1 +>dno : number +>sin : { [n: number]: number; } + + diff --git a/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.js b/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.js index 973e9756425de..1a34eb39c0ec4 100644 --- a/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.js +++ b/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.js @@ -1,5 +1,6 @@ //// [computerPropertiesInES5ShouldBeTransformed.ts] -const b = ({ [`key`]: renamed }) => renamed; +const b = ({ [`key`]: renamed }) => renamed; + //// [computerPropertiesInES5ShouldBeTransformed.js] var b = function (_a) { diff --git a/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.types b/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.types index b0e4e1424acce..8e1d05a159cb8 100644 --- a/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.types +++ b/tests/baselines/reference/computerPropertiesInES5ShouldBeTransformed.types @@ -1,7 +1,7 @@ === tests/cases/compiler/computerPropertiesInES5ShouldBeTransformed.ts === const b = ({ [`key`]: renamed }) => renamed; ->b : ({ [`key`]: renamed }: {}) => any ->({ [`key`]: renamed }) => renamed : ({ [`key`]: renamed }: {}) => any +>b : ({ [`key`]: renamed }: { key: any; }) => any +>({ [`key`]: renamed }) => renamed : ({ [`key`]: renamed }: { key: any; }) => any >`key` : "key" >renamed : any >renamed : any diff --git a/tests/baselines/reference/exportDefaultParenthesize.types b/tests/baselines/reference/exportDefaultParenthesize.types index 43e016a9ea039..e3dc8b9fdba1d 100644 --- a/tests/baselines/reference/exportDefaultParenthesize.types +++ b/tests/baselines/reference/exportDefaultParenthesize.types @@ -144,7 +144,7 @@ export default { === tests/cases/compiler/comma.ts === export default { ->{ ['foo']: 42} : { ['foo']: number; } +>{ ['foo']: 42} : { ["foo"]: number; } ['foo']: 42 >'foo' : "foo" diff --git a/tests/baselines/reference/literalsInComputedProperties1.symbols b/tests/baselines/reference/literalsInComputedProperties1.symbols index 501b969706ab7..7eb00aba6911c 100644 --- a/tests/baselines/reference/literalsInComputedProperties1.symbols +++ b/tests/baselines/reference/literalsInComputedProperties1.symbols @@ -19,7 +19,7 @@ x[1].toExponential(); x[2].toExponential(); >x[2].toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) >x : Symbol(x, Decl(literalsInComputedProperties1.ts, 0, 3)) ->2 : Symbol([2], Decl(literalsInComputedProperties1.ts, 1, 8)) +>2 : Symbol(["2"], Decl(literalsInComputedProperties1.ts, 1, 8)) >toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) x[3].toExponential(); diff --git a/tests/baselines/reference/literalsInComputedProperties1.types b/tests/baselines/reference/literalsInComputedProperties1.types index d258e71d6fc66..860bf880e54d0 100644 --- a/tests/baselines/reference/literalsInComputedProperties1.types +++ b/tests/baselines/reference/literalsInComputedProperties1.types @@ -1,7 +1,7 @@ === tests/cases/compiler/literalsInComputedProperties1.ts === let x = { ->x : { 1: number; [2]: number; "3": number; ["4"]: number; } ->{ 1:1, [2]:1, "3":1, ["4"]:1} : { 1: number; [2]: number; "3": number; ["4"]: number; } +>x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } +>{ 1:1, [2]:1, "3":1, ["4"]:1} : { 1: number; ["2"]: number; "3": number; ["4"]: number; } 1:1, >1 : 1 @@ -21,7 +21,7 @@ x[1].toExponential(); >x[1].toExponential() : string >x[1].toExponential : (fractionDigits?: number) => string >x[1] : number ->x : { 1: number; [2]: number; "3": number; ["4"]: number; } +>x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } >1 : 1 >toExponential : (fractionDigits?: number) => string @@ -29,7 +29,7 @@ x[2].toExponential(); >x[2].toExponential() : string >x[2].toExponential : (fractionDigits?: number) => string >x[2] : number ->x : { 1: number; [2]: number; "3": number; ["4"]: number; } +>x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } >2 : 2 >toExponential : (fractionDigits?: number) => string @@ -37,7 +37,7 @@ x[3].toExponential(); >x[3].toExponential() : string >x[3].toExponential : (fractionDigits?: number) => string >x[3] : number ->x : { 1: number; [2]: number; "3": number; ["4"]: number; } +>x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } >3 : 3 >toExponential : (fractionDigits?: number) => string @@ -45,7 +45,7 @@ x[4].toExponential(); >x[4].toExponential() : string >x[4].toExponential : (fractionDigits?: number) => string >x[4] : number ->x : { 1: number; [2]: number; "3": number; ["4"]: number; } +>x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } >4 : 4 >toExponential : (fractionDigits?: number) => string diff --git a/tests/baselines/reference/objectLiteralEnumPropertyNames.types b/tests/baselines/reference/objectLiteralEnumPropertyNames.types index 460d96bc56dcf..2ae3f898f3b42 100644 --- a/tests/baselines/reference/objectLiteralEnumPropertyNames.types +++ b/tests/baselines/reference/objectLiteralEnumPropertyNames.types @@ -52,7 +52,7 @@ const ux = { const y: TestStrs = { >y : TestStrs >TestStrs : TestStrs ->{ ['a']: 'yo', ['b']: 'ye'} : { ['a']: string; ['b']: string; } +>{ ['a']: 'yo', ['b']: 'ye'} : { ["a"]: string; ["b"]: string; } ['a']: 'yo', >'a' : "a" diff --git a/tests/baselines/reference/objectSpread.types b/tests/baselines/reference/objectSpread.types index 1f87ed4930d24..30513ee1762ee 100644 --- a/tests/baselines/reference/objectSpread.types +++ b/tests/baselines/reference/objectSpread.types @@ -521,7 +521,7 @@ function container( >b : string { ['before everything']: 12, ...o, b: 'yes' } ->{ ['before everything']: 12, ...o, b: 'yes' } : { b: string; a: number; ['before everything']: number; } +>{ ['before everything']: 12, ...o, b: 'yes' } : { b: string; a: number; ["before everything"]: number; } >'before everything' : "before everything" >12 : 12 >o : { a: number; b: string; } @@ -535,7 +535,7 @@ function container( >c : boolean { ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } ->{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { b: string; c: boolean; ['in the middle']: number; a: number; } +>{ ...o, ['in the middle']: 13, b: 'maybe?', ...o2 } : { b: string; c: boolean; ["in the middle"]: number; a: number; } >o : { a: number; b: string; } >'in the middle' : "in the middle" >13 : 13 @@ -549,7 +549,7 @@ function container( >b : string { ...o, b: 'yeah', ['at the end']: 14 } ->{ ...o, b: 'yeah', ['at the end']: 14 } : { b: string; ['at the end']: number; a: number; } +>{ ...o, b: 'yeah', ['at the end']: 14 } : { b: string; ["at the end"]: number; a: number; } >o : { a: number; b: string; } >b : string >'yeah' : "yeah" diff --git a/tests/baselines/reference/parserComputedPropertyName35.types b/tests/baselines/reference/parserComputedPropertyName35.types index e1be4b2ba676f..836ac699cef1c 100644 --- a/tests/baselines/reference/parserComputedPropertyName35.types +++ b/tests/baselines/reference/parserComputedPropertyName35.types @@ -1,7 +1,7 @@ === tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName35.ts === var x = { ->x : { [0, 1]: {}; } ->{ [0, 1]: { }} : { [0, 1]: {}; } +>x : { ["1"]: {}; } +>{ [0, 1]: { }} : { ["1"]: {}; } [0, 1]: { } >0, 1 : 1 diff --git a/tests/baselines/reference/parserComputedPropertyName41.types b/tests/baselines/reference/parserComputedPropertyName41.types index 5300d79e4b082..8d186bd96f310 100644 --- a/tests/baselines/reference/parserComputedPropertyName41.types +++ b/tests/baselines/reference/parserComputedPropertyName41.types @@ -1,7 +1,7 @@ === tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName41.ts === var v = { ->v : { [0 in []]: boolean; } | { [0 in []]: boolean; } ->{ [0 in []]: true} : { [0 in []]: boolean; } | { [0 in []]: boolean; } +>v : { ["true"]: boolean; } | { ["false"]: boolean; } +>{ [0 in []]: true} : { ["true"]: boolean; } | { ["false"]: boolean; } [0 in []]: true >0 in [] : boolean diff --git a/tests/cases/compiler/computerPropertiesInES5ShouldBeTransformed.ts b/tests/cases/compiler/computerPropertiesInES5ShouldBeTransformed.ts index 42eb602989dfe..16e3c10e9c2f6 100644 --- a/tests/cases/compiler/computerPropertiesInES5ShouldBeTransformed.ts +++ b/tests/cases/compiler/computerPropertiesInES5ShouldBeTransformed.ts @@ -1,2 +1,2 @@ // @target: es5 -const b = ({ [`key`]: renamed }) => renamed; \ No newline at end of file +const b = ({ [`key`]: renamed }) => renamed; diff --git a/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts index 3e315c349c122..2f7652f59d6ed 100644 --- a/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts +++ b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts @@ -1,25 +1,54 @@ +// @noImplicitAny: true +// @target: es6 declare var ab: 'a' | 'b'; declare var cd: 'c' | 'd'; -// More cases: -// add spreads -// other literal types: number, boolean, enum (string and number) -// multiple unions -// union, spread (with union inside), union -// methods and other stuff that would get mangled by spread (since I use spread internally) +declare var onetwo: 1 | 2; +enum Alphabet { + Aleph, + Bet, +} +declare var alphabet: Alphabet; + const x: { a: string } | { b: string } = { [ab]: 'hi' } +// multiple unions const y: { a: string, m: number, c: string } | { a: string, m: number, d: string } | { b: string, m: number, c: string } | { b: string, m: number, d: string } = { [ab]: 'hi', m: 1, [cd]: 'there' } +// union, spread (with union inside), union +const s: { a: string, c: string } | { b: string, c: string } = { [ab]: 'hi', ...{ c: 'no' }} +const sd: { a: string } | { b: string } = { [ab]: 'hi', ...{ a: 'no' }} +const sn: { a: string, c: string } + | { a: string, d: string } + | { b: string, c: string } + | { b: string, d: string } = { [ab]: 'hi', ...{ [cd]: 'no' }} +// methods +const m: { a: string, m(): number, p: number } | { b: string, m(): number, p: number } = + { [ab]: 'hi', m() { return 1 }, get p() { return 2 } } +// other literal types: number, enum (string and number) +const n: { "1": string } | { "2": string } = { [onetwo]: 'hi' } +const e: { "0": string } | { "1": string } = { [alphabet]: 'hi' } -// in destructuring???!! -/* -declare let o: { [t]: string } +// destructuring declare let u: { a: string } | { b: string } -const { [t]: doo } = o -const { [t]: duo } = u -var t: 'a' | 'b' = doo -var t: 'a' | 'b' = duo -*/ +({ [ab]: du } = u) // implicit any error +var du: any +declare let sig: { [s: string]: string } +({ [ab]: ds } = sig) // fine, comes from index signature +var ds: string + +var duo: any +var dso: string +var { [ab]: duo } = u // implicit any error (or similar to the singleton one) +var { [ab]: dso } = sig // fine + +// number index signatures +declare let sin: { [n: number]: number } +var dn: number +({ [onetwo]: dn } = sin) // fine, from index signature +var dno: number +var { [onetwo]: dno } = sin // fine, from index signature + + From c242f206b73d3c15ae36910c514d1e151e0e6354 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 8 Jan 2018 09:37:20 -0800 Subject: [PATCH 06/14] Improve spread type parameter names --- src/compiler/checker.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3bb55ba410ee6..af7e167540b98 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3192,7 +3192,7 @@ namespace ts { !((symbol as TransientSymbol).checkFlags & CheckFlags.Late) && !isWellKnownSymbolSyntactically((name as ComputedPropertyName).expression) && symbol.escapedName) { - return "[\"" + unescapeLeadingUnderscores(symbol.escapedName) + "\"]"; + return '["' + unescapeLeadingUnderscores(symbol.escapedName) + '"]'; } return declarationNameToString(name); } @@ -6023,11 +6023,11 @@ namespace ts { getIntersectionType([info1.type, info2.type]), info1.isReadonly && info2.isReadonly); } - function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo, looseIndexes: boolean): IndexInfo { + function unionSpreadIndexInfos(info1: IndexInfo, info2: IndexInfo, allowSingleIndex: boolean): IndexInfo { if (info1 && info2) { return createIndexInfo(getUnionType([info1.type, info2.type]), info1.isReadonly || info2.isReadonly); } - if (looseIndexes) { + if (allowSingleIndex) { return info1 ? info1 : info2 ? info2 : undefined; } } @@ -8389,7 +8389,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol, propagatedFlags: TypeFlags, looseIndexes: boolean): Type { + function getSpreadType(left: Type, right: Type, symbol: Symbol, propagatedFlags: TypeFlags, fromComputedProperty: boolean): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -8400,10 +8400,10 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - return mapType(left, t => getSpreadType(t, right, symbol, propagatedFlags, looseIndexes)); + return mapType(left, t => getSpreadType(t, right, symbol, propagatedFlags, fromComputedProperty)); } if (right.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t, symbol, propagatedFlags, looseIndexes)); + return mapType(right, t => getSpreadType(left, t, symbol, propagatedFlags, fromComputedProperty)); } if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive)) { return left; @@ -8419,8 +8419,8 @@ namespace ts { numberIndexInfo = getIndexInfoOfType(right, IndexKind.Number); } else { - stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String), looseIndexes); - numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number), looseIndexes); + stringIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.String), getIndexInfoOfType(right, IndexKind.String), fromComputedProperty); + numberIndexInfo = unionSpreadIndexInfos(getIndexInfoOfType(left, IndexKind.Number), getIndexInfoOfType(right, IndexKind.Number), fromComputedProperty); } for (const rightProp of getPropertiesOfType(right)) { @@ -14708,14 +14708,14 @@ namespace ts { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - updateIntermediateType(getSpreadType(intermediate, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ false)); + updateIntermediateType(getSpreadType(intermediate, createObjectLiteralType(), node.symbol, propagatedFlags, /*fromComputedProperty*/ false)); } const type = checkExpression((memberDecl as SpreadAssignment).expression); if (!isValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } - intermediate = getSpreadType(intermediate, type, node.symbol, propagatedFlags, /*looseIndexes*/ false); + intermediate = getSpreadType(intermediate, type, node.symbol, propagatedFlags, /*fromComputedProperty*/ false); offset = i + 1; continue; } @@ -14760,7 +14760,7 @@ namespace ts { if (intermediate !== emptyObjectType) { if (propertiesArray.length > 0) { - intermediate = getSpreadType(intermediate, createObjectLiteralType(), node.symbol, propagatedFlags, /*looseIndexes*/ hasUnionedComputedProperty); + intermediate = getSpreadType(intermediate, createObjectLiteralType(), node.symbol, propagatedFlags, /*fromComputedProperty*/ hasUnionedComputedProperty); } return intermediate; } @@ -14794,7 +14794,7 @@ namespace ts { propertiesTable.delete(prop.escapedName); } } - return getSpreadType(intermediate, getUnionType(types), node.symbol, propagatedFlags, /*looseIndexes*/ true); + return getSpreadType(intermediate, getUnionType(types), node.symbol, propagatedFlags, /*fromComputedProperty*/ true); } // TODO: Probably don't need the second parameter @@ -14970,7 +14970,7 @@ namespace ts { else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes, /*fromComputedProperty*/ false); attributesTable = createSymbolTable(); } const exprType = checkExpressionCached(attributeDecl.expression, checkMode); @@ -14978,7 +14978,7 @@ namespace ts { hasSpreadAnyType = true; } if (isValidSpreadType(exprType)) { - spread = getSpreadType(spread, exprType, openingLikeElement.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); + spread = getSpreadType(spread, exprType, openingLikeElement.symbol, TypeFlags.JsxAttributes, /*fromComputedProperty*/ false); } else { typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; @@ -14988,7 +14988,7 @@ namespace ts { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, TypeFlags.JsxAttributes, /*fromComputedProperty*/ false); } } @@ -15013,7 +15013,7 @@ namespace ts { createArrayType(getUnionType(childrenTypes)); const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); - spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), attributes.symbol, TypeFlags.JsxAttributes, /*looseIndexes*/ false); + spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), attributes.symbol, TypeFlags.JsxAttributes, /*fromComputedProperty*/ false); } } From 59095cdaea4dc63f5d8addfc8872aa0216c30a07 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 8 Jan 2018 09:53:50 -0800 Subject: [PATCH 07/14] Further improve readability of checkObjectLiteral --- src/compiler/checker.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index af7e167540b98..aa83aa8cc2815 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14658,15 +14658,11 @@ namespace ts { let offset = 0; for (let i = 0; i < node.properties.length; i++) { const memberDecl = node.properties[i]; - let member = getSymbolOfNode(memberDecl); + let member: Symbol; let literalName: __String[] | __String | undefined; if (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment || isObjectLiteralMethod(memberDecl)) { - let jsdocType: Type; - if (isInJSFile) { - jsdocType = getTypeForDeclarationFromJSDocComment(memberDecl); - } let type: Type; if (memberDecl.kind === SyntaxKind.PropertyAssignment) { @@ -14689,19 +14685,22 @@ namespace ts { type = checkExpressionForMutableLocation((memberDecl).name, checkMode); } - if (jsdocType) { - checkTypeAssignableTo(type, jsdocType, memberDecl); - type = jsdocType; + if (isInJSFile) { + const jsdocType = getTypeForDeclarationFromJSDocComment(memberDecl); + if (jsdocType) { + checkTypeAssignableTo(type, jsdocType, memberDecl); + type = jsdocType; + } } typeFlags |= type.flags; if (isArray(literalName)) { hasUnionedComputedProperty = true; - updateIntermediateType(getUnionFromLiteralUnion(memberDecl, member, literalName, type)); + updateIntermediateType(getUnionFromLiteralUnion(memberDecl, literalName, type)); continue; } - member = createProperty(memberDecl, member, literalName, type); + member = createProperty(memberDecl, literalName, type); } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { if (languageVersion < ScriptTarget.ES2015) { @@ -14729,6 +14728,7 @@ namespace ts { checkNodeDeferred(memberDecl); } + member = member || getSymbolOfNode(memberDecl); if (!literalName && hasNonBindableDynamicName(memberDecl)) { if (isNumericName(memberDecl.name)) { hasComputedNumberProperty = true; @@ -14773,10 +14773,10 @@ namespace ts { propertiesTable = createSymbolTable(); } - function getUnionFromLiteralUnion(memberDecl: ObjectLiteralElementLike, member: Symbol, literalNames: __String[], type: Type) { + function getUnionFromLiteralUnion(memberDecl: ObjectLiteralElementLike, literalNames: __String[], type: Type) { const types: Type[] = []; for (const literalName of literalNames) { - const prop = createProperty(memberDecl, member, literalName, type); + const prop = createProperty(memberDecl, literalName, type); propertiesArray.push(prop); let duplicate: Symbol; if (propertiesTable.has(prop.escapedName)) { @@ -14797,8 +14797,8 @@ namespace ts { return getSpreadType(intermediate, getUnionType(types), node.symbol, propagatedFlags, /*fromComputedProperty*/ true); } - // TODO: Probably don't need the second parameter - function createProperty(memberDecl: ObjectLiteralElementLike, member: Symbol, literalName: __String, type: Type) { + function createProperty(memberDecl: ObjectLiteralElementLike, literalName: __String, type: Type) { + const member = getSymbolOfNode(memberDecl); const nameType = hasLateBindableName(memberDecl) ? checkComputedPropertyName(memberDecl.name) : undefined; const prop = nameType && isTypeUsableAsLateBoundName(nameType) ? createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType), CheckFlags.Late) From 25f981fe7334ce3126c9cc79b1db4edbde3a255c Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Jan 2018 09:21:26 -0800 Subject: [PATCH 08/14] Print computer numeric literal property names as numeric --- src/compiler/checker.ts | 6 ++++-- .../reference/computedPropertyNames10_ES5.types | 4 ++-- .../reference/computedPropertyNames10_ES6.types | 4 ++-- .../reference/computedPropertyNames46_ES5.types | 4 ++-- .../reference/computedPropertyNames46_ES6.types | 4 ++-- .../reference/computedPropertyNames47_ES5.types | 4 ++-- .../reference/computedPropertyNames47_ES6.types | 4 ++-- .../reference/computedPropertyNames48_ES5.types | 2 +- .../reference/computedPropertyNames48_ES6.types | 2 +- .../reference/computedPropertyNames4_ES5.types | 4 ++-- .../reference/computedPropertyNames4_ES6.types | 4 ++-- .../computedPropertyUnionLiftsToUnionType.types | 6 +++--- .../reference/literalsInComputedProperties1.symbols | 4 ++-- .../reference/literalsInComputedProperties1.types | 12 ++++++------ .../reference/parserComputedPropertyName35.types | 4 ++-- .../TypeScript-Node-Starter/TypeScript-Node-Starter | 2 +- 16 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index aa83aa8cc2815..7697c193d1804 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3191,8 +3191,10 @@ namespace ts { symbol.flags & SymbolFlags.Transient && !((symbol as TransientSymbol).checkFlags & CheckFlags.Late) && !isWellKnownSymbolSyntactically((name as ComputedPropertyName).expression) && - symbol.escapedName) { - return '["' + unescapeLeadingUnderscores(symbol.escapedName) + '"]'; + symbol.escapedName !== undefined) { + return isNumericLiteralName(symbol.escapedName) ? + "[" + symbol.escapedName + "]" : + '["' + unescapeLeadingUnderscores(symbol.escapedName) + '"]'; } return declarationNameToString(name); } diff --git a/tests/baselines/reference/computedPropertyNames10_ES5.types b/tests/baselines/reference/computedPropertyNames10_ES5.types index f76476e4e55da..4750d44fde8b2 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES5.types +++ b/tests/baselines/reference/computedPropertyNames10_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } ->{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } +>v : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } +>{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } [s]() { }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames10_ES6.types b/tests/baselines/reference/computedPropertyNames10_ES6.types index b294517022c92..3a12047f588fe 100644 --- a/tests/baselines/reference/computedPropertyNames10_ES6.types +++ b/tests/baselines/reference/computedPropertyNames10_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } ->{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; ["0"](): void; } +>v : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } +>{ [s]() { }, [n]() { }, [s + s]() { }, [s + n]() { }, [+s]() { }, [""]() { }, [0]() { }, [a]() { }, [true]() { }, [`hello bye`]() { }, [`hello ${a} bye`]() { }} : { [x: string]: () => void; [x: number]: () => void; [""](): void; [0](): void; } [s]() { }, >s : string diff --git a/tests/baselines/reference/computedPropertyNames46_ES5.types b/tests/baselines/reference/computedPropertyNames46_ES5.types index d57d03ee79b5a..0e8b1b345d39e 100644 --- a/tests/baselines/reference/computedPropertyNames46_ES5.types +++ b/tests/baselines/reference/computedPropertyNames46_ES5.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNames46_ES5.ts === var o = { ->o : { ["0"]: number; } ->{ ["" || 0]: 0} : { ["0"]: number; } +>o : { [0]: number; } +>{ ["" || 0]: 0} : { [0]: number; } ["" || 0]: 0 >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames46_ES6.types b/tests/baselines/reference/computedPropertyNames46_ES6.types index ef3ae6eef845e..68f31dc4068c9 100644 --- a/tests/baselines/reference/computedPropertyNames46_ES6.types +++ b/tests/baselines/reference/computedPropertyNames46_ES6.types @@ -1,7 +1,7 @@ === tests/cases/conformance/es6/computedProperties/computedPropertyNames46_ES6.ts === var o = { ->o : { ["0"]: number; } ->{ ["" || 0]: 0} : { ["0"]: number; } +>o : { [0]: number; } +>{ ["" || 0]: 0} : { [0]: number; } ["" || 0]: 0 >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames47_ES5.types b/tests/baselines/reference/computedPropertyNames47_ES5.types index 0b0e4580d7f46..48029d1ad0b29 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES5.types +++ b/tests/baselines/reference/computedPropertyNames47_ES5.types @@ -8,8 +8,8 @@ enum E2 { x } >x : E2 var o = { ->o : { ["0"]: number; } ->{ [E1.x || E2.x]: 0} : { ["0"]: number; } +>o : { [0]: number; } +>{ [E1.x || E2.x]: 0} : { [0]: number; } [E1.x || E2.x]: 0 >E1.x || E2.x : E2 diff --git a/tests/baselines/reference/computedPropertyNames47_ES6.types b/tests/baselines/reference/computedPropertyNames47_ES6.types index bd594bb56c285..c544096e43049 100644 --- a/tests/baselines/reference/computedPropertyNames47_ES6.types +++ b/tests/baselines/reference/computedPropertyNames47_ES6.types @@ -8,8 +8,8 @@ enum E2 { x } >x : E2 var o = { ->o : { ["0"]: number; } ->{ [E1.x || E2.x]: 0} : { ["0"]: number; } +>o : { [0]: number; } +>{ [E1.x || E2.x]: 0} : { [0]: number; } [E1.x || E2.x]: 0 >E1.x || E2.x : E2 diff --git a/tests/baselines/reference/computedPropertyNames48_ES5.types b/tests/baselines/reference/computedPropertyNames48_ES5.types index 0e61fa9dfa2d3..651507d797e06 100644 --- a/tests/baselines/reference/computedPropertyNames48_ES5.types +++ b/tests/baselines/reference/computedPropertyNames48_ES5.types @@ -41,7 +41,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ ["" || 0]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ ["" || 0]: ""} : { ["0"]: string; } +>{ ["" || 0]: ""} : { [0]: string; } ["" || 0]: "" >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames48_ES6.types b/tests/baselines/reference/computedPropertyNames48_ES6.types index d29494a430084..e207209e48bf7 100644 --- a/tests/baselines/reference/computedPropertyNames48_ES6.types +++ b/tests/baselines/reference/computedPropertyNames48_ES6.types @@ -41,7 +41,7 @@ extractIndexer({ extractIndexer({ >extractIndexer({ ["" || 0]: ""}) : string >extractIndexer : (p: { [n: number]: T; }) => T ->{ ["" || 0]: ""} : { ["0"]: string; } +>{ ["" || 0]: ""} : { [0]: string; } ["" || 0]: "" >"" || 0 : 0 diff --git a/tests/baselines/reference/computedPropertyNames4_ES5.types b/tests/baselines/reference/computedPropertyNames4_ES5.types index 83cdf869bc580..c37d2b8f6b63f 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES5.types +++ b/tests/baselines/reference/computedPropertyNames4_ES5.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } +>v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; ["hello bye"]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; ["hello bye"]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyNames4_ES6.types b/tests/baselines/reference/computedPropertyNames4_ES6.types index 35a160bd86a80..90a7cc526d7c7 100644 --- a/tests/baselines/reference/computedPropertyNames4_ES6.types +++ b/tests/baselines/reference/computedPropertyNames4_ES6.types @@ -9,8 +9,8 @@ var a: any; >a : any var v = { ->v : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } ->{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; ["0"]: number; ["hello bye"]: number; } +>v : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; ["hello bye"]: number; } +>{ [s]: 0, [n]: n, [s + s]: 1, [s + n]: 2, [+s]: s, [""]: 0, [0]: 0, [a]: 1, [true]: 0, [`hello bye`]: 0, [`hello ${a} bye`]: 0} : { [x: string]: string | number; [x: number]: string | number; [""]: number; [0]: number; ["hello bye"]: number; } [s]: 0, >s : string diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types index 9379d25eba7ee..8943c8bff54b9 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types @@ -128,13 +128,13 @@ const m: { a: string, m(): number, p: number } | { b: string, m(): number, p: nu // other literal types: number, enum (string and number) const n: { "1": string } | { "2": string } = { [onetwo]: 'hi' } >n : { "1": string; } | { "2": string; } ->{ [onetwo]: 'hi' } : { ["2"]: string; } | { ["1"]: string; } +>{ [onetwo]: 'hi' } : { [2]: string; } | { [1]: string; } >onetwo : 2 | 1 >'hi' : "hi" const e: { "0": string } | { "1": string } = { [alphabet]: 'hi' } >e : { "0": string; } | { "1": string; } ->{ [alphabet]: 'hi' } : { ["0"]: string; } | { ["1"]: string; } +>{ [alphabet]: 'hi' } : { [0]: string; } | { [1]: string; } >alphabet : Alphabet >'hi' : "hi" @@ -197,7 +197,7 @@ var dn: number ({ [onetwo]: dn } = sin) // fine, from index signature >({ [onetwo]: dn } = sin) : { [n: number]: number; } >{ [onetwo]: dn } = sin : { [n: number]: number; } ->{ [onetwo]: dn } : { ["2"]: number; } | { ["1"]: number; } +>{ [onetwo]: dn } : { [2]: number; } | { [1]: number; } >onetwo : 2 | 1 >dn : number >sin : { [n: number]: number; } diff --git a/tests/baselines/reference/literalsInComputedProperties1.symbols b/tests/baselines/reference/literalsInComputedProperties1.symbols index 7eb00aba6911c..e3d47c90330c1 100644 --- a/tests/baselines/reference/literalsInComputedProperties1.symbols +++ b/tests/baselines/reference/literalsInComputedProperties1.symbols @@ -19,7 +19,7 @@ x[1].toExponential(); x[2].toExponential(); >x[2].toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) >x : Symbol(x, Decl(literalsInComputedProperties1.ts, 0, 3)) ->2 : Symbol(["2"], Decl(literalsInComputedProperties1.ts, 1, 8)) +>2 : Symbol([2], Decl(literalsInComputedProperties1.ts, 1, 8)) >toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) x[3].toExponential(); @@ -31,7 +31,7 @@ x[3].toExponential(); x[4].toExponential(); >x[4].toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) >x : Symbol(x, Decl(literalsInComputedProperties1.ts, 0, 3)) ->4 : Symbol(["4"], Decl(literalsInComputedProperties1.ts, 3, 10)) +>4 : Symbol([4], Decl(literalsInComputedProperties1.ts, 3, 10)) >toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) interface A { diff --git a/tests/baselines/reference/literalsInComputedProperties1.types b/tests/baselines/reference/literalsInComputedProperties1.types index 860bf880e54d0..1a2246da0ac19 100644 --- a/tests/baselines/reference/literalsInComputedProperties1.types +++ b/tests/baselines/reference/literalsInComputedProperties1.types @@ -1,7 +1,7 @@ === tests/cases/compiler/literalsInComputedProperties1.ts === let x = { ->x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } ->{ 1:1, [2]:1, "3":1, ["4"]:1} : { 1: number; ["2"]: number; "3": number; ["4"]: number; } +>x : { 1: number; [2]: number; "3": number; [4]: number; } +>{ 1:1, [2]:1, "3":1, ["4"]:1} : { 1: number; [2]: number; "3": number; [4]: number; } 1:1, >1 : 1 @@ -21,7 +21,7 @@ x[1].toExponential(); >x[1].toExponential() : string >x[1].toExponential : (fractionDigits?: number) => string >x[1] : number ->x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } +>x : { 1: number; [2]: number; "3": number; [4]: number; } >1 : 1 >toExponential : (fractionDigits?: number) => string @@ -29,7 +29,7 @@ x[2].toExponential(); >x[2].toExponential() : string >x[2].toExponential : (fractionDigits?: number) => string >x[2] : number ->x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } +>x : { 1: number; [2]: number; "3": number; [4]: number; } >2 : 2 >toExponential : (fractionDigits?: number) => string @@ -37,7 +37,7 @@ x[3].toExponential(); >x[3].toExponential() : string >x[3].toExponential : (fractionDigits?: number) => string >x[3] : number ->x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } +>x : { 1: number; [2]: number; "3": number; [4]: number; } >3 : 3 >toExponential : (fractionDigits?: number) => string @@ -45,7 +45,7 @@ x[4].toExponential(); >x[4].toExponential() : string >x[4].toExponential : (fractionDigits?: number) => string >x[4] : number ->x : { 1: number; ["2"]: number; "3": number; ["4"]: number; } +>x : { 1: number; [2]: number; "3": number; [4]: number; } >4 : 4 >toExponential : (fractionDigits?: number) => string diff --git a/tests/baselines/reference/parserComputedPropertyName35.types b/tests/baselines/reference/parserComputedPropertyName35.types index 836ac699cef1c..8aa053f498b79 100644 --- a/tests/baselines/reference/parserComputedPropertyName35.types +++ b/tests/baselines/reference/parserComputedPropertyName35.types @@ -1,7 +1,7 @@ === tests/cases/conformance/parser/ecmascript6/ComputedPropertyNames/parserComputedPropertyName35.ts === var x = { ->x : { ["1"]: {}; } ->{ [0, 1]: { }} : { ["1"]: {}; } +>x : { [1]: {}; } +>{ [0, 1]: { }} : { [1]: {}; } [0, 1]: { } >0, 1 : 1 diff --git a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter index 40bdb4eadabc9..ed149eb0c787b 160000 --- a/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter +++ b/tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter @@ -1 +1 @@ -Subproject commit 40bdb4eadabc9fbed7d83e3f26817a931c0763b6 +Subproject commit ed149eb0c787b1195a95b44105822c64bb6eb636 From c69c4ff9c8f56d7ce491fe54111ede24e77ae5c7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Jan 2018 09:51:31 -0800 Subject: [PATCH 09/14] Improve destructuring:str/num computed properties Also add declaration baselines for computedPropertyUnionLiftsToUnionType --- src/compiler/checker.ts | 13 ++- ...edPropertyUnionLiftsToUnionType.errors.txt | 4 - .../computedPropertyUnionLiftsToUnionType.js | 101 +++++++++++++++++- ...putedPropertyUnionLiftsToUnionType.symbols | 4 - ...omputedPropertyUnionLiftsToUnionType.types | 4 - .../computedPropertyUnionLiftsToUnionType.ts | 10 +- 6 files changed, 117 insertions(+), 19 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7697c193d1804..0e11d55663bf7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4320,6 +4320,12 @@ namespace ts { type = (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); } + else if (computedType.flags & TypeFlags.Number) { + type = getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); + } + else if (computedType.flags & TypeFlags.String) { + type = getIndexTypeOfType(parentType, IndexKind.String); + } else { return anyType; } @@ -14811,7 +14817,6 @@ namespace ts { const isOptional = (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue((memberDecl).initializer)) || (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && (memberDecl).objectAssignmentInitializer); if (isOptional) { - prop.flags |= SymbolFlags.Optional; } if (!literalName && hasDynamicName(memberDecl)) { @@ -18681,6 +18686,12 @@ namespace ts { : (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); } + else if (computedType.flags & TypeFlags.Number) { + type = getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); + } + else if (computedType.flags & TypeFlags.String) { + type = getIndexTypeOfType(objectLiteralType, IndexKind.String); + } else { return undefined; } diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt index f5869070e2090..736b365864243 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt @@ -55,8 +55,4 @@ tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnion ({ [onetwo]: dn } = sin) // fine, from index signature var dno: number var { [onetwo]: dno } = sin // fine, from index signature - - - - \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js index 969e10599802f..f6ff572d79157 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js @@ -47,10 +47,6 @@ var dn: number ({ [onetwo]: dn } = sin) // fine, from index signature var dno: number var { [onetwo]: dno } = sin // fine, from index signature - - - - //// [computedPropertyUnionLiftsToUnionType.js] @@ -83,3 +79,100 @@ var dn; ({ [onetwo]: dn } = sin); // fine, from index signature var dno; var { [onetwo]: dno } = sin; // fine, from index signature + + +//// [computedPropertyUnionLiftsToUnionType.d.ts] +declare var ab: 'a' | 'b'; +declare var cd: 'c' | 'd'; +declare var onetwo: 1 | 2; +declare enum Alphabet { + Aleph = 0, + Bet = 1, +} +declare var alphabet: Alphabet; +declare const x: { + a: string; +} | { + b: string; +}; +declare const y: { + a: string; + m: number; + c: string; +} | { + a: string; + m: number; + d: string; +} | { + b: string; + m: number; + c: string; +} | { + b: string; + m: number; + d: string; +}; +declare const s: { + a: string; + c: string; +} | { + b: string; + c: string; +}; +declare const sd: { + a: string; +} | { + b: string; +}; +declare const sn: { + a: string; + c: string; +} | { + a: string; + d: string; +} | { + b: string; + c: string; +} | { + b: string; + d: string; +}; +declare const m: { + a: string; + m(): number; + p: number; +} | { + b: string; + m(): number; + p: number; +}; +declare const n: { + "1": string; +} | { + "2": string; +}; +declare const e: { + "0": string; +} | { + "1": string; +}; +declare let u: { + a: string; +} | { + b: string; +}; +declare var du: any; +declare let sig: { + [s: string]: string; +}; +declare var ds: string; +declare var duo: any; +declare var dso: string; +declare var duo: any; +declare var dso: string; +declare let sin: { + [n: number]: number; +}; +declare var dn: number; +declare var dno: number; +declare var dno: number; diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols index ae4eab628e0a8..1d9e2329279e4 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols @@ -175,7 +175,3 @@ var { [onetwo]: dno } = sin // fine, from index signature >dno : Symbol(dno, Decl(computedPropertyUnionLiftsToUnionType.ts, 46, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 47, 5)) >sin : Symbol(sin, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 11)) - - - - diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types index 8943c8bff54b9..7a72d08222206 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types @@ -210,7 +210,3 @@ var { [onetwo]: dno } = sin // fine, from index signature >dno : number >sin : { [n: number]: number; } - - - - diff --git a/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts index 2f7652f59d6ed..e5147dfef736d 100644 --- a/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts +++ b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts @@ -1,5 +1,6 @@ // @noImplicitAny: true // @target: es6 +// @declaration: true declare var ab: 'a' | 'b'; declare var cd: 'c' | 'd'; declare var onetwo: 1 | 2; @@ -49,6 +50,11 @@ var dn: number var dno: number var { [onetwo]: dno } = sin // fine, from index signature +declare const textMap: {[key: string]: string} - - +function getText (s: string, n: number) { + var { [s]: rawText = s } = sig; + var { [n]: rawNumber = n } = sin; + ({ [s]: rawText } = sig); + ({ [n]: rawNumber } = sin); +} From ddd9714d792e539607cd356454ba99751d893a8b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Jan 2018 13:20:22 -0800 Subject: [PATCH 10/14] Error reporting:improve destructured computed properties --- src/compiler/checker.ts | 31 ++++++++++- ...edPropertyUnionLiftsToUnionType.errors.txt | 28 ++++++++-- .../computedPropertyUnionLiftsToUnionType.js | 24 +++++++++ ...putedPropertyUnionLiftsToUnionType.symbols | 41 +++++++++++++++ ...omputedPropertyUnionLiftsToUnionType.types | 52 +++++++++++++++++++ .../computedPropertyUnionLiftsToUnionType.ts | 3 ++ 6 files changed, 172 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0e11d55663bf7..1754ee794d7b2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4306,6 +4306,7 @@ namespace ts { const name = declaration.propertyName || declaration.name; if (isComputedNonLiteralName(name)) { const computedType = checkComputedPropertyName(name); + let errorName: __String | undefined; if (!computedType) { return anyType; } @@ -4315,18 +4316,30 @@ namespace ts { type = declaredType && getFlowTypeOfReference(declaration, declaredType) || computedType.flags & TypeFlags.NumberLiteral && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); + errorName = text; } else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { type = (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); + errorName = (computedType as UnionType).types[0] && getTextOfPropertyLiteralType((computedType as UnionType).types[0]); } else if (computedType.flags & TypeFlags.Number) { type = getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); + errorName = undefined; } else if (computedType.flags & TypeFlags.String) { type = getIndexTypeOfType(parentType, IndexKind.String); + errorName = undefined; } - else { + if (!type) { + if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { + if (errorName) { + error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), unescapeLeadingUnderscores(errorName)); + } + else { + error(name, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(parentType)); + } + } return anyType; } } @@ -18669,6 +18682,7 @@ namespace ts { const computedType = name.kind === SyntaxKind.ComputedPropertyName ? checkComputedPropertyName(name) : undefined; let type: Type; if (isComputedNonLiteralName(name)) { + let errorName: __String | undefined; if (!computedType) { return undefined; } @@ -18679,22 +18693,35 @@ namespace ts { : getTypeOfPropertyOfType(objectLiteralType, text) || computedType.flags & TypeFlags.NumberLiteral && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); + errorName = text; } else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { type = isTypeAny(objectLiteralType) ? objectLiteralType : (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); + errorName = (computedType as UnionType).types[0] && getTextOfPropertyLiteralType((computedType as UnionType).types[0]); } else if (computedType.flags & TypeFlags.Number) { type = getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); + errorName = undefined; } else if (computedType.flags & TypeFlags.String) { type = getIndexTypeOfType(objectLiteralType, IndexKind.String); + errorName = undefined; } - else { + if (!type) { + if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { + if (errorName) { + error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), unescapeLeadingUnderscores(errorName)); + } + else { + error(name, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectLiteralType)); + } + } return undefined; } + } else { const text = getTextOfPropertyName(name); diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt index 736b365864243..74494b50a22b7 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.errors.txt @@ -1,8 +1,10 @@ -tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(32,4): error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. -tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(40,7): error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. +tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(32,4): error TS2459: Type '{ a: string; } | { b: string; }' has no property 'a' and no string index signature. +tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(40,7): error TS2459: Type '{ a: string; } | { b: string; }' has no property 'a' and no string index signature. +tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(58,11): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. +tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts(59,8): error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. -==== tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts (2 errors) ==== +==== tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts (4 errors) ==== declare var ab: 'a' | 'b'; declare var cd: 'c' | 'd'; declare var onetwo: 1 | 2; @@ -36,7 +38,7 @@ tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnion declare let u: { a: string } | { b: string } ({ [ab]: du } = u) // implicit any error ~~~~ -!!! error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. +!!! error TS2459: Type '{ a: string; } | { b: string; }' has no property 'a' and no string index signature. var du: any declare let sig: { [s: string]: string } ({ [ab]: ds } = sig) // fine, comes from index signature @@ -46,7 +48,7 @@ tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnion var dso: string var { [ab]: duo } = u // implicit any error (or similar to the singleton one) ~~~~ -!!! error TS2459: Type '{ a: string; } | { b: string; }' has no property '[ab]' and no string index signature. +!!! error TS2459: Type '{ a: string; } | { b: string; }' has no property 'a' and no string index signature. var { [ab]: dso } = sig // fine // number index signatures @@ -55,4 +57,20 @@ tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnion ({ [onetwo]: dn } = sin) // fine, from index signature var dno: number var { [onetwo]: dno } = sin // fine, from index signature + + // # 16789 + declare const textMap: {[key: string]: string} + + function getText (s: string, n: number) { + var { [s]: rawText = s } = sig; + var { [n]: rawNumber = n } = sin; + ({ [s]: rawText } = sig); + ({ [n]: rawNumber } = sin); + var { [s]: noSig } = {}; + ~~~ +!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. + ({ [s]: noSig } = {}); + ~~~ +!!! error TS7017: Element implicitly has an 'any' type because type '{}' has no index signature. + } \ No newline at end of file diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js index f6ff572d79157..1809ab0ac4c4a 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.js @@ -47,6 +47,18 @@ var dn: number ({ [onetwo]: dn } = sin) // fine, from index signature var dno: number var { [onetwo]: dno } = sin // fine, from index signature + +// # 16789 +declare const textMap: {[key: string]: string} + +function getText (s: string, n: number) { + var { [s]: rawText = s } = sig; + var { [n]: rawNumber = n } = sin; + ({ [s]: rawText } = sig); + ({ [n]: rawNumber } = sin); + var { [s]: noSig } = {}; + ({ [s]: noSig } = {}); +} //// [computedPropertyUnionLiftsToUnionType.js] @@ -79,6 +91,14 @@ var dn; ({ [onetwo]: dn } = sin); // fine, from index signature var dno; var { [onetwo]: dno } = sin; // fine, from index signature +function getText(s, n) { + var { [s]: rawText = s } = sig; + var { [n]: rawNumber = n } = sin; + ({ [s]: rawText } = sig); + ({ [n]: rawNumber } = sin); + var { [s]: noSig } = {}; + ({ [s]: noSig } = {}); +} //// [computedPropertyUnionLiftsToUnionType.d.ts] @@ -176,3 +196,7 @@ declare let sin: { declare var dn: number; declare var dno: number; declare var dno: number; +declare const textMap: { + [key: string]: string; +}; +declare function getText(s: string, n: number): void; diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols index 1d9e2329279e4..9ea5445c99447 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.symbols @@ -175,3 +175,44 @@ var { [onetwo]: dno } = sin // fine, from index signature >dno : Symbol(dno, Decl(computedPropertyUnionLiftsToUnionType.ts, 46, 3), Decl(computedPropertyUnionLiftsToUnionType.ts, 47, 5)) >sin : Symbol(sin, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 11)) +// # 16789 +declare const textMap: {[key: string]: string} +>textMap : Symbol(textMap, Decl(computedPropertyUnionLiftsToUnionType.ts, 50, 13)) +>key : Symbol(key, Decl(computedPropertyUnionLiftsToUnionType.ts, 50, 25)) + +function getText (s: string, n: number) { +>getText : Symbol(getText, Decl(computedPropertyUnionLiftsToUnionType.ts, 50, 46)) +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 18)) +>n : Symbol(n, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 28)) + + var { [s]: rawText = s } = sig; +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 18)) +>rawText : Symbol(rawText, Decl(computedPropertyUnionLiftsToUnionType.ts, 53, 9)) +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 18)) +>sig : Symbol(sig, Decl(computedPropertyUnionLiftsToUnionType.ts, 33, 11)) + + var { [n]: rawNumber = n } = sin; +>n : Symbol(n, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 28)) +>rawNumber : Symbol(rawNumber, Decl(computedPropertyUnionLiftsToUnionType.ts, 54, 9)) +>n : Symbol(n, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 28)) +>sin : Symbol(sin, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 11)) + + ({ [s]: rawText } = sig); +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 18)) +>rawText : Symbol(rawText, Decl(computedPropertyUnionLiftsToUnionType.ts, 53, 9)) +>sig : Symbol(sig, Decl(computedPropertyUnionLiftsToUnionType.ts, 33, 11)) + + ({ [n]: rawNumber } = sin); +>n : Symbol(n, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 28)) +>rawNumber : Symbol(rawNumber, Decl(computedPropertyUnionLiftsToUnionType.ts, 54, 9)) +>sin : Symbol(sin, Decl(computedPropertyUnionLiftsToUnionType.ts, 43, 11)) + + var { [s]: noSig } = {}; +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 18)) +>noSig : Symbol(noSig, Decl(computedPropertyUnionLiftsToUnionType.ts, 57, 9)) + + ({ [s]: noSig } = {}); +>s : Symbol(s, Decl(computedPropertyUnionLiftsToUnionType.ts, 52, 18)) +>noSig : Symbol(noSig, Decl(computedPropertyUnionLiftsToUnionType.ts, 57, 9)) +} + diff --git a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types index 7a72d08222206..4942e5e751f1d 100644 --- a/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types +++ b/tests/baselines/reference/computedPropertyUnionLiftsToUnionType.types @@ -210,3 +210,55 @@ var { [onetwo]: dno } = sin // fine, from index signature >dno : number >sin : { [n: number]: number; } +// # 16789 +declare const textMap: {[key: string]: string} +>textMap : { [key: string]: string; } +>key : string + +function getText (s: string, n: number) { +>getText : (s: string, n: number) => void +>s : string +>n : number + + var { [s]: rawText = s } = sig; +>s : string +>rawText : string +>s : string +>sig : { [s: string]: string; } + + var { [n]: rawNumber = n } = sin; +>n : number +>rawNumber : number +>n : number +>sin : { [n: number]: number; } + + ({ [s]: rawText } = sig); +>({ [s]: rawText } = sig) : { [s: string]: string; } +>{ [s]: rawText } = sig : { [s: string]: string; } +>{ [s]: rawText } : { [x: string]: string; } +>s : string +>rawText : string +>sig : { [s: string]: string; } + + ({ [n]: rawNumber } = sin); +>({ [n]: rawNumber } = sin) : { [n: number]: number; } +>{ [n]: rawNumber } = sin : { [n: number]: number; } +>{ [n]: rawNumber } : { [x: number]: number; } +>n : number +>rawNumber : number +>sin : { [n: number]: number; } + + var { [s]: noSig } = {}; +>s : string +>noSig : any +>{} : {} + + ({ [s]: noSig } = {}); +>({ [s]: noSig } = {}) : {} +>{ [s]: noSig } = {} : {} +>{ [s]: noSig } : { [x: string]: any; } +>s : string +>noSig : any +>{} : {} +} + diff --git a/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts index e5147dfef736d..7b45df3307f82 100644 --- a/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts +++ b/tests/cases/conformance/es6/computedProperties/computedPropertyUnionLiftsToUnionType.ts @@ -50,6 +50,7 @@ var dn: number var dno: number var { [onetwo]: dno } = sin // fine, from index signature +// # 16789 declare const textMap: {[key: string]: string} function getText (s: string, n: number) { @@ -57,4 +58,6 @@ function getText (s: string, n: number) { var { [n]: rawNumber = n } = sin; ({ [s]: rawText } = sig); ({ [n]: rawNumber } = sin); + var { [s]: noSig } = {}; + ({ [s]: noSig } = {}); } From ea8fc7c657cebf33598306377d3fea4be8a61bf5 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Jan 2018 14:05:00 -0800 Subject: [PATCH 11/14] Computed properties with null and undefined literals --- src/compiler/checker.ts | 46 ++++++++----------- .../computedPropertyNames5_ES5.types | 4 +- .../computedPropertyNames5_ES6.types | 4 +- 3 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1754ee794d7b2..ce08a5df68b52 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4310,18 +4310,15 @@ namespace ts { if (!computedType) { return anyType; } - else if (computedType.flags & TypeFlags.Literal) { - const text = getTextOfPropertyLiteralType(computedType); - const declaredType = getTypeOfPropertyOfType(parentType, text); + else if (isLiteralType(computedType)) { + const text = !(computedType.flags & TypeFlags.Union) && getTextOfPropertyLiteralType(computedType); + const declaredType = text && getTypeOfPropertyOfType(parentType, text); + const isNumeric = computedType.flags & TypeFlags.NumberLiteral || + computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)); type = declaredType && getFlowTypeOfReference(declaration, declaredType) || - computedType.flags & TypeFlags.NumberLiteral && getIndexTypeOfType(parentType, IndexKind.Number) || + isNumeric && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); - errorName = text; - } - else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { - type = (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(parentType, IndexKind.Number) || - getIndexTypeOfType(parentType, IndexKind.String); - errorName = (computedType as UnionType).types[0] && getTextOfPropertyLiteralType((computedType as UnionType).types[0]); + errorName = computedType.flags & TypeFlags.Union && (computedType as UnionType).types.length ? getTextOfPropertyLiteralType((computedType as UnionType).types[0]) : text; } else if (computedType.flags & TypeFlags.Number) { type = getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); @@ -14689,11 +14686,10 @@ namespace ts { if (memberDecl.kind === SyntaxKind.PropertyAssignment) { if (memberDecl.name.kind === SyntaxKind.ComputedPropertyName) { const computedType = checkComputedPropertyName(memberDecl.name); - if (computedType.flags & TypeFlags.Literal) { - literalName = getTextOfPropertyLiteralType(computedType); - } - else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { - literalName = (computedType as UnionType).types.map(getTextOfPropertyLiteralType); + if (isLiteralType(computedType)) { + literalName = computedType.flags & TypeFlags.Union ? + (computedType as UnionType).types.map(getTextOfPropertyLiteralType) : + getTextOfPropertyLiteralType(computedType); } } type = checkPropertyAssignment(memberDecl, checkMode); @@ -18686,21 +18682,16 @@ namespace ts { if (!computedType) { return undefined; } - else if (computedType.flags & TypeFlags.Literal) { - const text = getTextOfPropertyLiteralType(computedType); - type = isTypeAny(objectLiteralType) - ? objectLiteralType - : getTypeOfPropertyOfType(objectLiteralType, text) || - computedType.flags & TypeFlags.NumberLiteral && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || - getIndexTypeOfType(objectLiteralType, IndexKind.String); - errorName = text; - } - else if (computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.Literal))) { + else if (isLiteralType(computedType)) { + const text = !(computedType.flags & TypeFlags.Union) && getTextOfPropertyLiteralType(computedType); + const isNumeric = computedType.flags & TypeFlags.NumberLiteral || + computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)); type = isTypeAny(objectLiteralType) ? objectLiteralType - : (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || + : text && getTypeOfPropertyOfType(objectLiteralType, text) || + isNumeric && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); - errorName = (computedType as UnionType).types[0] && getTextOfPropertyLiteralType((computedType as UnionType).types[0]); + errorName = computedType.flags & TypeFlags.Union && (computedType as UnionType).types.length ? getTextOfPropertyLiteralType((computedType as UnionType).types[0]) : text; } else if (computedType.flags & TypeFlags.Number) { type = getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); @@ -18721,7 +18712,6 @@ namespace ts { } return undefined; } - } else { const text = getTextOfPropertyName(name); diff --git a/tests/baselines/reference/computedPropertyNames5_ES5.types b/tests/baselines/reference/computedPropertyNames5_ES5.types index f47c9383a901f..d095ada7fed08 100644 --- a/tests/baselines/reference/computedPropertyNames5_ES5.types +++ b/tests/baselines/reference/computedPropertyNames5_ES5.types @@ -3,8 +3,8 @@ var b: boolean; >b : boolean var v = { ->v : { [x: string]: number; [x: number]: any; ["true"]: number; } | { [x: string]: number; [x: number]: any; ["true"]: number; ["false"]: number; } ->{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; ["true"]: number; } | { [x: string]: number; [x: number]: null; ["true"]: number; ["false"]: number; } +>v : { [x: string]: number; ["true"]: number; ["undefined"]: any; ["null"]: any; } | { [x: string]: number; ["true"]: number; ["undefined"]: any; ["null"]: any; ["false"]: number; } +>{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; ["true"]: number; ["undefined"]: undefined; ["null"]: null; } | { [x: string]: number; ["true"]: number; ["undefined"]: undefined; ["null"]: null; ["false"]: number; } [b]: 0, >b : boolean diff --git a/tests/baselines/reference/computedPropertyNames5_ES6.types b/tests/baselines/reference/computedPropertyNames5_ES6.types index be0b018e91e82..d746195d15217 100644 --- a/tests/baselines/reference/computedPropertyNames5_ES6.types +++ b/tests/baselines/reference/computedPropertyNames5_ES6.types @@ -3,8 +3,8 @@ var b: boolean; >b : boolean var v = { ->v : { [x: string]: number; [x: number]: any; ["true"]: number; } | { [x: string]: number; [x: number]: any; ["true"]: number; ["false"]: number; } ->{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; [x: number]: null; ["true"]: number; } | { [x: string]: number; [x: number]: null; ["true"]: number; ["false"]: number; } +>v : { [x: string]: number; ["true"]: number; ["undefined"]: any; ["null"]: any; } | { [x: string]: number; ["true"]: number; ["undefined"]: any; ["null"]: any; ["false"]: number; } +>{ [b]: 0, [true]: 1, [[]]: 0, [{}]: 0, [undefined]: undefined, [null]: null} : { [x: string]: number; ["true"]: number; ["undefined"]: undefined; ["null"]: null; } | { [x: string]: number; ["true"]: number; ["undefined"]: undefined; ["null"]: null; ["false"]: number; } [b]: 0, >b : boolean From 772c75b3d0dbaf0a13c55a83e4956e62c253fbba Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Jan 2018 14:52:29 -0800 Subject: [PATCH 12/14] Combine destructured computed property checking --- src/compiler/checker.ts | 105 ++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 64 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ce08a5df68b52..b358673641956 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4236,7 +4236,7 @@ namespace ts { return symbol && getSymbolLinks(symbol).type || getTypeForVariableLikeDeclaration(node, /*includeOptionality*/ false); } - function isComputedNonLiteralName(name: PropertyName): boolean { + function isComputedNonLiteralName(name: PropertyName): name is ComputedPropertyName { return name.kind === SyntaxKind.ComputedPropertyName && !isStringOrNumericLiteral((name).expression); } @@ -4305,38 +4305,11 @@ namespace ts { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) const name = declaration.propertyName || declaration.name; if (isComputedNonLiteralName(name)) { - const computedType = checkComputedPropertyName(name); - let errorName: __String | undefined; - if (!computedType) { - return anyType; - } - else if (isLiteralType(computedType)) { - const text = !(computedType.flags & TypeFlags.Union) && getTextOfPropertyLiteralType(computedType); - const declaredType = text && getTypeOfPropertyOfType(parentType, text); - const isNumeric = computedType.flags & TypeFlags.NumberLiteral || - computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)); - type = declaredType && getFlowTypeOfReference(declaration, declaredType) || - isNumeric && getIndexTypeOfType(parentType, IndexKind.Number) || - getIndexTypeOfType(parentType, IndexKind.String); - errorName = computedType.flags & TypeFlags.Union && (computedType as UnionType).types.length ? getTextOfPropertyLiteralType((computedType as UnionType).types[0]) : text; - } - else if (computedType.flags & TypeFlags.Number) { - type = getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); - errorName = undefined; - } - else if (computedType.flags & TypeFlags.String) { - type = getIndexTypeOfType(parentType, IndexKind.String); - errorName = undefined; - } + type = checkComputedDestructuredProperty(parentType, name, (source, text) => { + const declaredType = getTypeOfPropertyOfType(source, text); + return declaredType && getFlowTypeOfReference(declaration, declaredType); + }); if (!type) { - if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { - if (errorName) { - error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), unescapeLeadingUnderscores(errorName)); - } - else { - error(name, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(parentType)); - } - } return anyType; } } @@ -18675,41 +18648,12 @@ namespace ts { function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: ReadonlyArray) { if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { const name = (property).name; - const computedType = name.kind === SyntaxKind.ComputedPropertyName ? checkComputedPropertyName(name) : undefined; let type: Type; if (isComputedNonLiteralName(name)) { - let errorName: __String | undefined; - if (!computedType) { - return undefined; - } - else if (isLiteralType(computedType)) { - const text = !(computedType.flags & TypeFlags.Union) && getTextOfPropertyLiteralType(computedType); - const isNumeric = computedType.flags & TypeFlags.NumberLiteral || - computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral)); - type = isTypeAny(objectLiteralType) - ? objectLiteralType - : text && getTypeOfPropertyOfType(objectLiteralType, text) || - isNumeric && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || - getIndexTypeOfType(objectLiteralType, IndexKind.String); - errorName = computedType.flags & TypeFlags.Union && (computedType as UnionType).types.length ? getTextOfPropertyLiteralType((computedType as UnionType).types[0]) : text; - } - else if (computedType.flags & TypeFlags.Number) { - type = getIndexTypeOfType(objectLiteralType, IndexKind.Number) || getIndexTypeOfType(objectLiteralType, IndexKind.String); - errorName = undefined; - } - else if (computedType.flags & TypeFlags.String) { - type = getIndexTypeOfType(objectLiteralType, IndexKind.String); - errorName = undefined; - } + type = checkComputedDestructuredProperty(objectLiteralType, name, (source, text) => { + return isTypeAny(source) ? anyType : getTypeOfPropertyOfType(source, text) + }); if (!type) { - if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { - if (errorName) { - error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), unescapeLeadingUnderscores(errorName)); - } - else { - error(name, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectLiteralType)); - } - } return undefined; } } @@ -18752,6 +18696,39 @@ namespace ts { } } + function checkComputedDestructuredProperty(source: Type, name: ComputedPropertyName, getSourcePropertyType: (source: Type, text: __String) => Type | undefined) { + const computedType = checkComputedPropertyName(name); + const isLiteral = isLiteralType(computedType); + const isNumeric = isLiteral && (computedType.flags & TypeFlags.NumberLiteral || + computedType.flags & TypeFlags.Union && (computedType as UnionType).types.every(t => !!(t.flags & TypeFlags.NumberLiteral))); + let type: Type | undefined; + let errorName: __String | undefined; + if (computedType.flags & (TypeFlags.String | TypeFlags.Number) || isLiteral) { + type = getIndexTypeOfType(source, IndexKind.String); + } + if (computedType.flags & TypeFlags.Number || isNumeric) { + type = getIndexTypeOfType(source, IndexKind.Number) || type; + } + if (isLiteral) { + const text = !(computedType.flags & TypeFlags.Union) && getTextOfPropertyLiteralType(computedType); + errorName = computedType.flags & TypeFlags.Union && (computedType as UnionType).types.length ? + getTextOfPropertyLiteralType((computedType as UnionType).types[0]) : + text; + type = text && getSourcePropertyType(source, text) || type; + } + if (!type) { + if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { + if (errorName) { + error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(source), unescapeLeadingUnderscores(errorName)); + } + else { + error(name, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(source)); + } + } + } + return type; + } + function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type { if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) { checkExternalEmitHelpers(node, ExternalEmitHelpers.Read); From 85e5054857ab22c6d16c2ae033cd1f3bc2be4bbc Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Jan 2018 14:57:59 -0800 Subject: [PATCH 13/14] Simplify parameter type Let callers rely on closure instead of passing in the source type unchanged to the lambda. --- src/compiler/checker.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b358673641956..ed9cd1dd22fb8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4305,8 +4305,8 @@ namespace ts { // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form) const name = declaration.propertyName || declaration.name; if (isComputedNonLiteralName(name)) { - type = checkComputedDestructuredProperty(parentType, name, (source, text) => { - const declaredType = getTypeOfPropertyOfType(source, text); + type = checkComputedDestructuredProperty(parentType, name, text => { + const declaredType = getTypeOfPropertyOfType(parentType, text); return declaredType && getFlowTypeOfReference(declaration, declaredType); }); if (!type) { @@ -18650,8 +18650,8 @@ namespace ts { const name = (property).name; let type: Type; if (isComputedNonLiteralName(name)) { - type = checkComputedDestructuredProperty(objectLiteralType, name, (source, text) => { - return isTypeAny(source) ? anyType : getTypeOfPropertyOfType(source, text) + type = checkComputedDestructuredProperty(objectLiteralType, name, text => { + return isTypeAny(objectLiteralType) ? anyType : getTypeOfPropertyOfType(objectLiteralType, text) }); if (!type) { return undefined; @@ -18696,7 +18696,7 @@ namespace ts { } } - function checkComputedDestructuredProperty(source: Type, name: ComputedPropertyName, getSourcePropertyType: (source: Type, text: __String) => Type | undefined) { + function checkComputedDestructuredProperty(source: Type, name: ComputedPropertyName, getSourcePropertyType: (text: __String) => Type | undefined) { const computedType = checkComputedPropertyName(name); const isLiteral = isLiteralType(computedType); const isNumeric = isLiteral && (computedType.flags & TypeFlags.NumberLiteral || @@ -18714,7 +18714,7 @@ namespace ts { errorName = computedType.flags & TypeFlags.Union && (computedType as UnionType).types.length ? getTextOfPropertyLiteralType((computedType as UnionType).types[0]) : text; - type = text && getSourcePropertyType(source, text) || type; + type = text && getSourcePropertyType(text) || type; } if (!type) { if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { From cd3b6887517fe8fdf79cdbb50b0a8fbc8d5d8d62 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 9 Jan 2018 15:07:46 -0800 Subject: [PATCH 14/14] Fix lint:add semicolon --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0dda195c6a9ea..c18f8eb9bc23d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18847,7 +18847,7 @@ namespace ts { let type: Type; if (isComputedNonLiteralName(name)) { type = checkComputedDestructuredProperty(objectLiteralType, name, text => { - return isTypeAny(objectLiteralType) ? anyType : getTypeOfPropertyOfType(objectLiteralType, text) + return isTypeAny(objectLiteralType) ? anyType : getTypeOfPropertyOfType(objectLiteralType, text); }); if (!type) { return undefined;