Merge pull request #31711 from microsoft/fixDestructuringWithFallback

Fix destructuring with fallback
This commit is contained in:
Anders Hejlsberg 2019-06-01 17:30:07 -07:00 committed by GitHub
commit d6c323a21b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 341 additions and 8 deletions

View File

@ -8016,10 +8016,13 @@ namespace ts {
else if (isUnion) {
const indexInfo = !isLateBoundName(name) && (isNumericLiteralName(name) && getIndexInfoOfType(type, IndexKind.Number) || getIndexInfoOfType(type, IndexKind.String));
if (indexInfo) {
checkFlags |= indexInfo.isReadonly ? CheckFlags.Readonly : 0;
checkFlags |= CheckFlags.WritePartial;
checkFlags |= CheckFlags.WritePartial | (indexInfo.isReadonly ? CheckFlags.Readonly : 0);
indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type);
}
else if (isObjectLiteralType(type)) {
checkFlags |= CheckFlags.WritePartial;
indexTypes = append(indexTypes, undefinedType);
}
else {
checkFlags |= CheckFlags.ReadPartial;
}
@ -18451,11 +18454,13 @@ namespace ts {
}
return contextSensitive === true ? getTypeOfExpression(left) : contextSensitive;
case SyntaxKind.BarBarToken:
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand,
// except for the special case of Javascript declarations of the form `namespace.prop = namespace.prop || {}`
// When an || expression has a contextual type, the operands are contextually typed by that type, except
// when that type originates in a binding pattern, the right operand is contextually typed by the type of
// the left operand. When an || expression has no contextual type, the right operand is contextually typed
// by the type of the left operand, except for the special case of Javascript declarations of the form
// `namespace.prop = namespace.prop || {}`.
const type = getContextualType(binaryExpression, contextFlags);
return !type && node === right && !isDefaultedExpandoInitializer(binaryExpression) ?
return node === right && (type && type.pattern || !type && !isDefaultedExpandoInitializer(binaryExpression)) ?
getTypeOfExpression(left) : type;
case SyntaxKind.AmpersandAmpersandToken:
case SyntaxKind.CommaToken:
@ -20195,7 +20200,8 @@ namespace ts {
let propType: Type;
const leftType = checkNonNullExpression(left);
const parentSymbol = getNodeLinks(left).resolvedSymbol;
const apparentType = getApparentType(getWidenedType(leftType));
// We widen array literals to get type any[] instead of undefined[] in non-strict mode
const apparentType = getApparentType(isEmptyArrayLiteralType(leftType) ? getWidenedType(leftType) : leftType);
if (isTypeAny(apparentType) || apparentType === silentNeverType) {
if (isIdentifier(left) && parentSymbol) {
markAliasReferenced(parentSymbol, node);

View File

@ -2,6 +2,34 @@
const a: { x?: number } = { };
let x = 0;
({x = 1} = a);
// Repro from #26235
function f1(options?: { color?: string, width?: number }) {
let { color, width } = options || {};
({ color, width } = options || {});
let x1 = (options || {}).color;
let x2 = (options || {})["color"];
}
function f2(options?: [string?, number?]) {
let [str, num] = options || [];
[str, num] = options || [];
let x1 = (options || {})[0];
}
function f3(options?: { color: string, width: number }) {
let { color, width } = options || {};
({ color, width } = options || {});
let x1 = (options || {}).color;
let x2 = (options || {})["color"];
}
function f4(options?: [string, number]) {
let [str, num] = options || [];
[str, num] = options || [];
let x1 = (options || {})[0];
}
//// [destructuringAssignmentWithDefault.js]
@ -9,3 +37,30 @@ var _a;
var a = {};
var x = 0;
(_a = a.x, x = _a === void 0 ? 1 : _a);
// Repro from #26235
function f1(options) {
var _a;
var _b = options || {}, color = _b.color, width = _b.width;
(_a = options || {}, color = _a.color, width = _a.width);
var x1 = (options || {}).color;
var x2 = (options || {})["color"];
}
function f2(options) {
var _a;
var _b = options || [], str = _b[0], num = _b[1];
_a = options || [], str = _a[0], num = _a[1];
var x1 = (options || {})[0];
}
function f3(options) {
var _a;
var _b = options || {}, color = _b.color, width = _b.width;
(_a = options || {}, color = _a.color, width = _a.width);
var x1 = (options || {}).color;
var x2 = (options || {})["color"];
}
function f4(options) {
var _a;
var _b = options || [], str = _b[0], num = _b[1];
_a = options || [], str = _a[0], num = _a[1];
var x1 = (options || {})[0];
}

View File

@ -10,3 +10,101 @@ let x = 0;
>x : Symbol(x, Decl(destructuringAssignmentWithDefault.ts, 2, 2))
>a : Symbol(a, Decl(destructuringAssignmentWithDefault.ts, 0, 5))
// Repro from #26235
function f1(options?: { color?: string, width?: number }) {
>f1 : Symbol(f1, Decl(destructuringAssignmentWithDefault.ts, 2, 14))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12))
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23))
>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 6, 39))
let { color, width } = options || {};
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 7, 9))
>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 7, 16))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12))
({ color, width } = options || {});
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 8, 6))
>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 8, 13))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12))
let x1 = (options || {}).color;
>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 9, 7))
>(options || {}).color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12))
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23))
let x2 = (options || {})["color"];
>x2 : Symbol(x2, Decl(destructuringAssignmentWithDefault.ts, 10, 7))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 6, 12))
>"color" : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 6, 23))
}
function f2(options?: [string?, number?]) {
>f2 : Symbol(f2, Decl(destructuringAssignmentWithDefault.ts, 11, 1))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12))
let [str, num] = options || [];
>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 14, 9))
>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 14, 13))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12))
[str, num] = options || [];
>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 14, 9))
>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 14, 13))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12))
let x1 = (options || {})[0];
>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 16, 7))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 13, 12))
>0 : Symbol(0)
}
function f3(options?: { color: string, width: number }) {
>f3 : Symbol(f3, Decl(destructuringAssignmentWithDefault.ts, 17, 1))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12))
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23))
>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 19, 38))
let { color, width } = options || {};
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 20, 9))
>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 20, 16))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12))
({ color, width } = options || {});
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 21, 6))
>width : Symbol(width, Decl(destructuringAssignmentWithDefault.ts, 21, 13))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12))
let x1 = (options || {}).color;
>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 22, 7))
>(options || {}).color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12))
>color : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23))
let x2 = (options || {})["color"];
>x2 : Symbol(x2, Decl(destructuringAssignmentWithDefault.ts, 23, 7))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 19, 12))
>"color" : Symbol(color, Decl(destructuringAssignmentWithDefault.ts, 19, 23))
}
function f4(options?: [string, number]) {
>f4 : Symbol(f4, Decl(destructuringAssignmentWithDefault.ts, 24, 1))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12))
let [str, num] = options || [];
>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 27, 9))
>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 27, 13))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12))
[str, num] = options || [];
>str : Symbol(str, Decl(destructuringAssignmentWithDefault.ts, 27, 9))
>num : Symbol(num, Decl(destructuringAssignmentWithDefault.ts, 27, 13))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12))
let x1 = (options || {})[0];
>x1 : Symbol(x1, Decl(destructuringAssignmentWithDefault.ts, 29, 7))
>options : Symbol(options, Decl(destructuringAssignmentWithDefault.ts, 26, 12))
>0 : Symbol(0)
}

View File

@ -16,3 +16,149 @@ let x = 0;
>1 : 1
>a : { x?: number | undefined; }
// Repro from #26235
function f1(options?: { color?: string, width?: number }) {
>f1 : (options?: { color?: string | undefined; width?: number | undefined; } | undefined) => void
>options : { color?: string | undefined; width?: number | undefined; } | undefined
>color : string | undefined
>width : number | undefined
let { color, width } = options || {};
>color : string | undefined
>width : number | undefined
>options || {} : { color?: string | undefined; width?: number | undefined; }
>options : { color?: string | undefined; width?: number | undefined; } | undefined
>{} : {}
({ color, width } = options || {});
>({ color, width } = options || {}) : { color?: string | undefined; width?: number | undefined; }
>{ color, width } = options || {} : { color?: string | undefined; width?: number | undefined; }
>{ color, width } : { color: string | undefined; width: number | undefined; }
>color : string | undefined
>width : number | undefined
>options || {} : { color?: string | undefined; width?: number | undefined; }
>options : { color?: string | undefined; width?: number | undefined; } | undefined
>{} : {}
let x1 = (options || {}).color;
>x1 : string | undefined
>(options || {}).color : string | undefined
>(options || {}) : { color?: string | undefined; width?: number | undefined; }
>options || {} : { color?: string | undefined; width?: number | undefined; }
>options : { color?: string | undefined; width?: number | undefined; } | undefined
>{} : {}
>color : string | undefined
let x2 = (options || {})["color"];
>x2 : string | undefined
>(options || {})["color"] : string | undefined
>(options || {}) : { color?: string | undefined; width?: number | undefined; }
>options || {} : { color?: string | undefined; width?: number | undefined; }
>options : { color?: string | undefined; width?: number | undefined; } | undefined
>{} : {}
>"color" : "color"
}
function f2(options?: [string?, number?]) {
>f2 : (options?: [(string | undefined)?, (number | undefined)?] | undefined) => void
>options : [(string | undefined)?, (number | undefined)?] | undefined
let [str, num] = options || [];
>str : string | undefined
>num : number | undefined
>options || [] : [(string | undefined)?, (number | undefined)?]
>options : [(string | undefined)?, (number | undefined)?] | undefined
>[] : []
[str, num] = options || [];
>[str, num] = options || [] : [(string | undefined)?, (number | undefined)?]
>[str, num] : [string | undefined, number | undefined]
>str : string | undefined
>num : number | undefined
>options || [] : [(string | undefined)?, (number | undefined)?]
>options : [(string | undefined)?, (number | undefined)?] | undefined
>[] : []
let x1 = (options || {})[0];
>x1 : string | undefined
>(options || {})[0] : string | undefined
>(options || {}) : [(string | undefined)?, (number | undefined)?] | {}
>options || {} : [(string | undefined)?, (number | undefined)?] | {}
>options : [(string | undefined)?, (number | undefined)?] | undefined
>{} : {}
>0 : 0
}
function f3(options?: { color: string, width: number }) {
>f3 : (options?: { color: string; width: number; } | undefined) => void
>options : { color: string; width: number; } | undefined
>color : string
>width : number
let { color, width } = options || {};
>color : string | undefined
>width : number | undefined
>options || {} : { color: string; width: number; } | {}
>options : { color: string; width: number; } | undefined
>{} : {}
({ color, width } = options || {});
>({ color, width } = options || {}) : { color: string; width: number; } | {}
>{ color, width } = options || {} : { color: string; width: number; } | {}
>{ color, width } : { color: string | undefined; width: number | undefined; }
>color : string | undefined
>width : number | undefined
>options || {} : { color: string; width: number; } | {}
>options : { color: string; width: number; } | undefined
>{} : {}
let x1 = (options || {}).color;
>x1 : string | undefined
>(options || {}).color : string | undefined
>(options || {}) : { color: string; width: number; } | {}
>options || {} : { color: string; width: number; } | {}
>options : { color: string; width: number; } | undefined
>{} : {}
>color : string | undefined
let x2 = (options || {})["color"];
>x2 : string | undefined
>(options || {})["color"] : string | undefined
>(options || {}) : { color: string; width: number; } | {}
>options || {} : { color: string; width: number; } | {}
>options : { color: string; width: number; } | undefined
>{} : {}
>"color" : "color"
}
function f4(options?: [string, number]) {
>f4 : (options?: [string, number] | undefined) => void
>options : [string, number] | undefined
let [str, num] = options || [];
>str : string | undefined
>num : number | undefined
>options || [] : [] | [string, number]
>options : [string, number] | undefined
>[] : []
[str, num] = options || [];
>[str, num] = options || [] : [] | [string, number]
>[str, num] : [string | undefined, number | undefined]
>str : string | undefined
>num : number | undefined
>options || [] : [] | [string, number]
>options : [string, number] | undefined
>[] : []
let x1 = (options || {})[0];
>x1 : string | undefined
>(options || {})[0] : string | undefined
>(options || {}) : [string, number] | {}
>options || {} : [string, number] | {}
>options : [string, number] | undefined
>{} : {}
>0 : 0
}

View File

@ -9,7 +9,7 @@ const [, a = ''] = ''.match('') || [];
>'' : ""
>match : (regexp: string | RegExp) => RegExpMatchArray
>'' : ""
>[] : [undefined?, ""?]
>[] : undefined[]
a.toFixed()
>a.toFixed() : any

View File

@ -2,3 +2,31 @@
const a: { x?: number } = { };
let x = 0;
({x = 1} = a);
// Repro from #26235
function f1(options?: { color?: string, width?: number }) {
let { color, width } = options || {};
({ color, width } = options || {});
let x1 = (options || {}).color;
let x2 = (options || {})["color"];
}
function f2(options?: [string?, number?]) {
let [str, num] = options || [];
[str, num] = options || [];
let x1 = (options || {})[0];
}
function f3(options?: { color: string, width: number }) {
let { color, width } = options || {};
({ color, width } = options || {});
let x1 = (options || {}).color;
let x2 = (options || {})["color"];
}
function f4(options?: [string, number]) {
let [str, num] = options || [];
[str, num] = options || [];
let x1 = (options || {})[0];
}