mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #3856 from Microsoft/widenTuples
Widening for tuples
This commit is contained in:
+30
-13
@@ -3943,7 +3943,7 @@ namespace ts {
|
||||
let id = getTypeListId(elementTypes);
|
||||
let type = tupleTypes[id];
|
||||
if (!type) {
|
||||
type = tupleTypes[id] = <TupleType>createObjectType(TypeFlags.Tuple);
|
||||
type = tupleTypes[id] = <TupleType>createObjectType(TypeFlags.Tuple | getWideningFlagsOfTypes(elementTypes));
|
||||
type.elementTypes = elementTypes;
|
||||
}
|
||||
return type;
|
||||
@@ -5299,8 +5299,8 @@ namespace ts {
|
||||
* Check if a Type was written as a tuple type literal.
|
||||
* Prefer using isTupleLikeType() unless the use of `elementTypes` is required.
|
||||
*/
|
||||
function isTupleType(type: Type): boolean {
|
||||
return (type.flags & TypeFlags.Tuple) && !!(<TupleType>type).elementTypes;
|
||||
function isTupleType(type: Type): type is TupleType {
|
||||
return !!(type.flags & TypeFlags.Tuple);
|
||||
}
|
||||
|
||||
function getWidenedTypeOfObjectLiteral(type: Type): Type {
|
||||
@@ -5341,26 +5341,45 @@ namespace ts {
|
||||
if (isArrayType(type)) {
|
||||
return createArrayType(getWidenedType((<TypeReference>type).typeArguments[0]));
|
||||
}
|
||||
if (isTupleType(type)) {
|
||||
return createTupleType(map(type.elementTypes, getWidenedType));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports implicit any errors that occur as a result of widening 'null' and 'undefined'
|
||||
* to 'any'. A call to reportWideningErrorsInType is normally accompanied by a call to
|
||||
* getWidenedType. But in some cases getWidenedType is called without reporting errors
|
||||
* (type argument inference is an example).
|
||||
*
|
||||
* The return value indicates whether an error was in fact reported. The particular circumstances
|
||||
* are on a best effort basis. Currently, if the null or undefined that causes widening is inside
|
||||
* an object literal property (arbitrarily deeply), this function reports an error. If no error is
|
||||
* reported, reportImplicitAnyError is a suitable fallback to report a general error.
|
||||
*/
|
||||
function reportWideningErrorsInType(type: Type): boolean {
|
||||
let errorReported = false;
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
let errorReported = false;
|
||||
forEach((<UnionType>type).types, t => {
|
||||
for (let t of (<UnionType>type).types) {
|
||||
if (reportWideningErrorsInType(t)) {
|
||||
errorReported = true;
|
||||
}
|
||||
});
|
||||
return errorReported;
|
||||
}
|
||||
}
|
||||
if (isArrayType(type)) {
|
||||
return reportWideningErrorsInType((<TypeReference>type).typeArguments[0]);
|
||||
}
|
||||
if (isTupleType(type)) {
|
||||
for (let t of type.elementTypes) {
|
||||
if (reportWideningErrorsInType(t)) {
|
||||
errorReported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type.flags & TypeFlags.ObjectLiteral) {
|
||||
let errorReported = false;
|
||||
forEach(getPropertiesOfObjectType(type), p => {
|
||||
for (let p of getPropertiesOfObjectType(type)) {
|
||||
let t = getTypeOfSymbol(p);
|
||||
if (t.flags & TypeFlags.ContainsUndefinedOrNull) {
|
||||
if (!reportWideningErrorsInType(t)) {
|
||||
@@ -5368,10 +5387,9 @@ namespace ts {
|
||||
}
|
||||
errorReported = true;
|
||||
}
|
||||
});
|
||||
return errorReported;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return errorReported;
|
||||
}
|
||||
|
||||
function reportImplicitAnyError(declaration: Declaration, type: Type) {
|
||||
@@ -6964,7 +6982,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function checkJsxSelfClosingElement(node: JsxSelfClosingElement) {
|
||||
checkJsxOpeningLikeElement(node);
|
||||
return jsxElementType || anyType;
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(32,4): error TS2345: Argument of type '[string, number, number]' is not assignable to parameter of type '[undefined, null, undefined]'.
|
||||
Types of property '0' are incompatible.
|
||||
Type 'string' is not assignable to type 'undefined'.
|
||||
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(33,4): error TS2345: Argument of type '[[string], number, [[boolean, boolean]]]' is not assignable to parameter of type '[[undefined], undefined, [[undefined, undefined]]]'.
|
||||
Types of property '0' are incompatible.
|
||||
Type '[string]' is not assignable to type '[undefined]'.
|
||||
Types of property '0' are incompatible.
|
||||
Type 'string' is not assignable to type 'undefined'.
|
||||
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(62,10): error TS2393: Duplicate function implementation.
|
||||
tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts(63,10): error TS2393: Duplicate function implementation.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts (4 errors) ====
|
||||
==== tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.ts (2 errors) ====
|
||||
// A parameter declaration may specify either an identifier or a binding pattern.
|
||||
// The identifiers specified in parameter declarations and binding patterns
|
||||
// in a parameter list must be unique within that parameter list.
|
||||
@@ -43,17 +35,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration1ES5.
|
||||
b2("string", { x: 200, y: "string" });
|
||||
b2("string", { x: 200, y: true });
|
||||
b6(["string", 1, 2]); // Shouldn't be an error
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '[string, number, number]' is not assignable to parameter of type '[undefined, null, undefined]'.
|
||||
!!! error TS2345: Types of property '0' are incompatible.
|
||||
!!! error TS2345: Type 'string' is not assignable to type 'undefined'.
|
||||
b7([["string"], 1, [[true, false]]]); // Shouldn't be an error
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '[[string], number, [[boolean, boolean]]]' is not assignable to parameter of type '[[undefined], undefined, [[undefined, undefined]]]'.
|
||||
!!! error TS2345: Types of property '0' are incompatible.
|
||||
!!! error TS2345: Type '[string]' is not assignable to type '[undefined]'.
|
||||
!!! error TS2345: Types of property '0' are incompatible.
|
||||
!!! error TS2345: Type 'string' is not assignable to type 'undefined'.
|
||||
|
||||
|
||||
// If the declaration specifies a binding pattern, the parameter type is the implied type of that binding pattern (section 5.1.3)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//// [wideningTuples1.ts]
|
||||
declare function foo<T extends [any]>(x: T): T;
|
||||
|
||||
var y = foo([undefined]);
|
||||
y = [""];
|
||||
|
||||
//// [wideningTuples1.js]
|
||||
var y = foo([undefined]);
|
||||
y = [""];
|
||||
@@ -0,0 +1,16 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples1.ts ===
|
||||
declare function foo<T extends [any]>(x: T): T;
|
||||
>foo : Symbol(foo, Decl(wideningTuples1.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(wideningTuples1.ts, 0, 21))
|
||||
>x : Symbol(x, Decl(wideningTuples1.ts, 0, 38))
|
||||
>T : Symbol(T, Decl(wideningTuples1.ts, 0, 21))
|
||||
>T : Symbol(T, Decl(wideningTuples1.ts, 0, 21))
|
||||
|
||||
var y = foo([undefined]);
|
||||
>y : Symbol(y, Decl(wideningTuples1.ts, 2, 3))
|
||||
>foo : Symbol(foo, Decl(wideningTuples1.ts, 0, 0))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
y = [""];
|
||||
>y : Symbol(y, Decl(wideningTuples1.ts, 2, 3))
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples1.ts ===
|
||||
declare function foo<T extends [any]>(x: T): T;
|
||||
>foo : <T extends [any]>(x: T) => T
|
||||
>T : T
|
||||
>x : T
|
||||
>T : T
|
||||
>T : T
|
||||
|
||||
var y = foo([undefined]);
|
||||
>y : [any]
|
||||
>foo([undefined]) : [any]
|
||||
>foo : <T extends [any]>(x: T) => T
|
||||
>[undefined] : [undefined]
|
||||
>undefined : undefined
|
||||
|
||||
y = [""];
|
||||
>y = [""] : [string]
|
||||
>y : [any]
|
||||
>[""] : [string]
|
||||
>"" : string
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
//// [wideningTuples2.ts]
|
||||
var foo: () => [any] = function bar() {
|
||||
let intermediate = bar();
|
||||
intermediate = [""];
|
||||
return [undefined];
|
||||
};
|
||||
|
||||
//// [wideningTuples2.js]
|
||||
var foo = function bar() {
|
||||
var intermediate = bar();
|
||||
intermediate = [""];
|
||||
return [undefined];
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples2.ts ===
|
||||
var foo: () => [any] = function bar() {
|
||||
>foo : Symbol(foo, Decl(wideningTuples2.ts, 0, 3))
|
||||
>bar : Symbol(bar, Decl(wideningTuples2.ts, 0, 22))
|
||||
|
||||
let intermediate = bar();
|
||||
>intermediate : Symbol(intermediate, Decl(wideningTuples2.ts, 1, 7))
|
||||
>bar : Symbol(bar, Decl(wideningTuples2.ts, 0, 22))
|
||||
|
||||
intermediate = [""];
|
||||
>intermediate : Symbol(intermediate, Decl(wideningTuples2.ts, 1, 7))
|
||||
|
||||
return [undefined];
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples2.ts ===
|
||||
var foo: () => [any] = function bar() {
|
||||
>foo : () => [any]
|
||||
>function bar() { let intermediate = bar(); intermediate = [""]; return [undefined];} : () => [any]
|
||||
>bar : () => [any]
|
||||
|
||||
let intermediate = bar();
|
||||
>intermediate : [any]
|
||||
>bar() : [any]
|
||||
>bar : () => [any]
|
||||
|
||||
intermediate = [""];
|
||||
>intermediate = [""] : [string]
|
||||
>intermediate : [any]
|
||||
>[""] : [string]
|
||||
>"" : string
|
||||
|
||||
return [undefined];
|
||||
>[undefined] : [undefined]
|
||||
>undefined : undefined
|
||||
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
tests/cases/conformance/types/tuple/wideningTuples3.ts(3,5): error TS7005: Variable 'b' implicitly has an '[any, any]' type.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/tuple/wideningTuples3.ts (1 errors) ====
|
||||
var a: [any];
|
||||
|
||||
var b = a = [undefined, null];
|
||||
~
|
||||
!!! error TS7005: Variable 'b' implicitly has an '[any, any]' type.
|
||||
@@ -0,0 +1,8 @@
|
||||
//// [wideningTuples3.ts]
|
||||
var a: [any];
|
||||
|
||||
var b = a = [undefined, null];
|
||||
|
||||
//// [wideningTuples3.js]
|
||||
var a;
|
||||
var b = a = [undefined, null];
|
||||
@@ -0,0 +1,10 @@
|
||||
//// [wideningTuples4.ts]
|
||||
var a: [any];
|
||||
|
||||
var b = a = [undefined, null];
|
||||
b = ["", ""];
|
||||
|
||||
//// [wideningTuples4.js]
|
||||
var a;
|
||||
var b = a = [undefined, null];
|
||||
b = ["", ""];
|
||||
@@ -0,0 +1,12 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples4.ts ===
|
||||
var a: [any];
|
||||
>a : Symbol(a, Decl(wideningTuples4.ts, 0, 3))
|
||||
|
||||
var b = a = [undefined, null];
|
||||
>b : Symbol(b, Decl(wideningTuples4.ts, 2, 3))
|
||||
>a : Symbol(a, Decl(wideningTuples4.ts, 0, 3))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
b = ["", ""];
|
||||
>b : Symbol(b, Decl(wideningTuples4.ts, 2, 3))
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples4.ts ===
|
||||
var a: [any];
|
||||
>a : [any]
|
||||
|
||||
var b = a = [undefined, null];
|
||||
>b : [any, any]
|
||||
>a = [undefined, null] : [undefined, null]
|
||||
>a : [any]
|
||||
>[undefined, null] : [undefined, null]
|
||||
>undefined : undefined
|
||||
>null : null
|
||||
|
||||
b = ["", ""];
|
||||
>b = ["", ""] : [string, string]
|
||||
>b : [any, any]
|
||||
>["", ""] : [string, string]
|
||||
>"" : string
|
||||
>"" : string
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
tests/cases/conformance/types/tuple/wideningTuples5.ts(1,6): error TS7005: Variable 'a' implicitly has an 'any' type.
|
||||
tests/cases/conformance/types/tuple/wideningTuples5.ts(1,9): error TS7005: Variable 'b' implicitly has an 'any' type.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/tuple/wideningTuples5.ts (2 errors) ====
|
||||
var [a, b] = [undefined, null];
|
||||
~
|
||||
!!! error TS7005: Variable 'a' implicitly has an 'any' type.
|
||||
~
|
||||
!!! error TS7005: Variable 'b' implicitly has an 'any' type.
|
||||
@@ -0,0 +1,5 @@
|
||||
//// [wideningTuples5.ts]
|
||||
var [a, b] = [undefined, null];
|
||||
|
||||
//// [wideningTuples5.js]
|
||||
var _a = [undefined, null], a = _a[0], b = _a[1];
|
||||
@@ -0,0 +1,9 @@
|
||||
//// [wideningTuples6.ts]
|
||||
var [a, b] = [undefined, null];
|
||||
a = "";
|
||||
b = "";
|
||||
|
||||
//// [wideningTuples6.js]
|
||||
var _a = [undefined, null], a = _a[0], b = _a[1];
|
||||
a = "";
|
||||
b = "";
|
||||
@@ -0,0 +1,12 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples6.ts ===
|
||||
var [a, b] = [undefined, null];
|
||||
>a : Symbol(a, Decl(wideningTuples6.ts, 0, 5))
|
||||
>b : Symbol(b, Decl(wideningTuples6.ts, 0, 7))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
a = "";
|
||||
>a : Symbol(a, Decl(wideningTuples6.ts, 0, 5))
|
||||
|
||||
b = "";
|
||||
>b : Symbol(b, Decl(wideningTuples6.ts, 0, 7))
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
=== tests/cases/conformance/types/tuple/wideningTuples6.ts ===
|
||||
var [a, b] = [undefined, null];
|
||||
>a : any
|
||||
>b : any
|
||||
>[undefined, null] : [undefined, null]
|
||||
>undefined : undefined
|
||||
>null : null
|
||||
|
||||
a = "";
|
||||
>a = "" : string
|
||||
>a : any
|
||||
>"" : string
|
||||
|
||||
b = "";
|
||||
>b = "" : string
|
||||
>b : any
|
||||
>"" : string
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
tests/cases/conformance/types/tuple/wideningTuples7.ts(1,20): error TS7010: 'bar', which lacks return-type annotation, implicitly has an '[any]' return type.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/tuple/wideningTuples7.ts (1 errors) ====
|
||||
var foo = function bar() {
|
||||
~~~
|
||||
!!! error TS7010: 'bar', which lacks return-type annotation, implicitly has an '[any]' return type.
|
||||
let intermediate: [string];
|
||||
return intermediate = [undefined];
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
//// [wideningTuples7.ts]
|
||||
var foo = function bar() {
|
||||
let intermediate: [string];
|
||||
return intermediate = [undefined];
|
||||
};
|
||||
|
||||
//// [wideningTuples7.js]
|
||||
var foo = function bar() {
|
||||
var intermediate;
|
||||
return intermediate = [undefined];
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
//@noImplicitAny: true
|
||||
declare function foo<T extends [any]>(x: T): T;
|
||||
|
||||
var y = foo([undefined]);
|
||||
y = [""];
|
||||
@@ -0,0 +1,6 @@
|
||||
//@noImplicitAny: true
|
||||
var foo: () => [any] = function bar() {
|
||||
let intermediate = bar();
|
||||
intermediate = [""];
|
||||
return [undefined];
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
//@noImplicitAny: true
|
||||
var a: [any];
|
||||
|
||||
var b = a = [undefined, null];
|
||||
@@ -0,0 +1,4 @@
|
||||
var a: [any];
|
||||
|
||||
var b = a = [undefined, null];
|
||||
b = ["", ""];
|
||||
@@ -0,0 +1,2 @@
|
||||
//@noImplicitAny: true
|
||||
var [a, b] = [undefined, null];
|
||||
@@ -0,0 +1,3 @@
|
||||
var [a, b] = [undefined, null];
|
||||
a = "";
|
||||
b = "";
|
||||
@@ -0,0 +1,5 @@
|
||||
//@noImplicitAny: true
|
||||
var foo = function bar() {
|
||||
let intermediate: [string];
|
||||
return intermediate = [undefined];
|
||||
};
|
||||
Reference in New Issue
Block a user