diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 193bb1d8c8099..e65d3fcac9146 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19789,7 +19789,13 @@ namespace ts { function isArrayLikeType(type: Type): boolean { // A type is array-like if it is a reference to the global Array or global ReadonlyArray type, // or if it is not the undefined or null type and if it is assignable to ReadonlyArray - return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); + return isArrayType(type) || hasArrayOrReadonlyArrayBaseType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType); + } + + function hasArrayOrReadonlyArrayBaseType(type: Type): boolean { + return !!(getObjectFlags(type) & ObjectFlags.Reference) + && !!(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface) + && some(getBaseTypes((type as TypeReference).target as InterfaceType), isArrayType); } function isEmptyArrayLiteralType(type: Type): boolean { diff --git a/tests/baselines/reference/excessiveStackDepthFlatArray.errors.txt b/tests/baselines/reference/excessiveStackDepthFlatArray.errors.txt new file mode 100644 index 0000000000000..825a402ca02c4 --- /dev/null +++ b/tests/baselines/reference/excessiveStackDepthFlatArray.errors.txt @@ -0,0 +1,48 @@ +tests/cases/compiler/index.tsx(35,13): error TS2322: Type '{ key: string; }' is not assignable to type 'HTMLAttributes'. + Property 'key' does not exist on type 'HTMLAttributes'. + + +==== tests/cases/compiler/index.tsx (1 errors) ==== + interface MiddlewareArray extends Array {} + declare function configureStore(options: { middleware: MiddlewareArray }): void; + + declare const defaultMiddleware: MiddlewareArray; + configureStore({ + middleware: [...defaultMiddleware], // Should not error + }); + + declare namespace React { + type DetailedHTMLProps, T> = E; + interface HTMLAttributes { + children?: ReactNode; + } + type ReactNode = ReactChild | ReactFragment | boolean | null | undefined; + type ReactText = string | number; + type ReactChild = ReactText; + type ReactFragment = {} | ReactNodeArray; + interface ReactNodeArray extends Array {} + } + declare namespace JSX { + interface IntrinsicElements { + ul: React.DetailedHTMLProps, HTMLUListElement>; + li: React.DetailedHTMLProps, HTMLLIElement>; + } + } + declare var React: any; + + const Component = () => { + const categories = ['Fruit', 'Vegetables']; + + return ( +
    +
  • All
  • + {categories.map((category) => ( +
  • {category}
  • // Error about 'key' only + ~~~ +!!! error TS2322: Type '{ key: string; }' is not assignable to type 'HTMLAttributes'. +!!! error TS2322: Property 'key' does not exist on type 'HTMLAttributes'. + ))} +
+ ); + }; + \ No newline at end of file diff --git a/tests/baselines/reference/excessiveStackDepthFlatArray.js b/tests/baselines/reference/excessiveStackDepthFlatArray.js new file mode 100644 index 0000000000000..4578612b4a630 --- /dev/null +++ b/tests/baselines/reference/excessiveStackDepthFlatArray.js @@ -0,0 +1,58 @@ +//// [index.tsx] +interface MiddlewareArray extends Array {} +declare function configureStore(options: { middleware: MiddlewareArray }): void; + +declare const defaultMiddleware: MiddlewareArray; +configureStore({ + middleware: [...defaultMiddleware], // Should not error +}); + +declare namespace React { + type DetailedHTMLProps, T> = E; + interface HTMLAttributes { + children?: ReactNode; + } + type ReactNode = ReactChild | ReactFragment | boolean | null | undefined; + type ReactText = string | number; + type ReactChild = ReactText; + type ReactFragment = {} | ReactNodeArray; + interface ReactNodeArray extends Array {} +} +declare namespace JSX { + interface IntrinsicElements { + ul: React.DetailedHTMLProps, HTMLUListElement>; + li: React.DetailedHTMLProps, HTMLLIElement>; + } +} +declare var React: any; + +const Component = () => { + const categories = ['Fruit', 'Vegetables']; + + return ( +
    +
  • All
  • + {categories.map((category) => ( +
  • {category}
  • // Error about 'key' only + ))} +
+ ); +}; + + +//// [index.js] +var __spreadArray = (this && this.__spreadArray) || function (to, from) { + for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) + to[j] = from[i]; + return to; +}; +configureStore({ + middleware: __spreadArray([], defaultMiddleware) +}); +var Component = function () { + var categories = ['Fruit', 'Vegetables']; + return (React.createElement("ul", null, + React.createElement("li", null, "All"), + categories.map(function (category) { return (React.createElement("li", { key: category }, category) // Error about 'key' only + ); }))); +}; diff --git a/tests/baselines/reference/excessiveStackDepthFlatArray.symbols b/tests/baselines/reference/excessiveStackDepthFlatArray.symbols new file mode 100644 index 0000000000000..08fe546e6da06 --- /dev/null +++ b/tests/baselines/reference/excessiveStackDepthFlatArray.symbols @@ -0,0 +1,128 @@ +=== tests/cases/compiler/index.tsx === +interface MiddlewareArray extends Array {} +>MiddlewareArray : Symbol(MiddlewareArray, Decl(index.tsx, 0, 0)) +>T : Symbol(T, Decl(index.tsx, 0, 26)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) +>T : Symbol(T, Decl(index.tsx, 0, 26)) + +declare function configureStore(options: { middleware: MiddlewareArray }): void; +>configureStore : Symbol(configureStore, Decl(index.tsx, 0, 48)) +>options : Symbol(options, Decl(index.tsx, 1, 32)) +>middleware : Symbol(middleware, Decl(index.tsx, 1, 42)) +>MiddlewareArray : Symbol(MiddlewareArray, Decl(index.tsx, 0, 0)) + +declare const defaultMiddleware: MiddlewareArray; +>defaultMiddleware : Symbol(defaultMiddleware, Decl(index.tsx, 3, 13)) +>MiddlewareArray : Symbol(MiddlewareArray, Decl(index.tsx, 0, 0)) + +configureStore({ +>configureStore : Symbol(configureStore, Decl(index.tsx, 0, 48)) + + middleware: [...defaultMiddleware], // Should not error +>middleware : Symbol(middleware, Decl(index.tsx, 4, 16)) +>defaultMiddleware : Symbol(defaultMiddleware, Decl(index.tsx, 3, 13)) + +}); + +declare namespace React { +>React : Symbol(React, Decl(index.tsx, 6, 3), Decl(index.tsx, 25, 11)) + + type DetailedHTMLProps, T> = E; +>DetailedHTMLProps : Symbol(DetailedHTMLProps, Decl(index.tsx, 8, 25)) +>E : Symbol(E, Decl(index.tsx, 9, 25)) +>HTMLAttributes : Symbol(HTMLAttributes, Decl(index.tsx, 9, 61)) +>T : Symbol(T, Decl(index.tsx, 9, 53)) +>T : Symbol(T, Decl(index.tsx, 9, 53)) +>E : Symbol(E, Decl(index.tsx, 9, 25)) + + interface HTMLAttributes { +>HTMLAttributes : Symbol(HTMLAttributes, Decl(index.tsx, 9, 61)) +>T : Symbol(T, Decl(index.tsx, 10, 27)) + + children?: ReactNode; +>children : Symbol(HTMLAttributes.children, Decl(index.tsx, 10, 31)) +>ReactNode : Symbol(ReactNode, Decl(index.tsx, 12, 3)) + } + type ReactNode = ReactChild | ReactFragment | boolean | null | undefined; +>ReactNode : Symbol(ReactNode, Decl(index.tsx, 12, 3)) +>ReactChild : Symbol(ReactChild, Decl(index.tsx, 14, 35)) +>ReactFragment : Symbol(ReactFragment, Decl(index.tsx, 15, 30)) + + type ReactText = string | number; +>ReactText : Symbol(ReactText, Decl(index.tsx, 13, 75)) + + type ReactChild = ReactText; +>ReactChild : Symbol(ReactChild, Decl(index.tsx, 14, 35)) +>ReactText : Symbol(ReactText, Decl(index.tsx, 13, 75)) + + type ReactFragment = {} | ReactNodeArray; +>ReactFragment : Symbol(ReactFragment, Decl(index.tsx, 15, 30)) +>ReactNodeArray : Symbol(ReactNodeArray, Decl(index.tsx, 16, 43)) + + interface ReactNodeArray extends Array {} +>ReactNodeArray : Symbol(ReactNodeArray, Decl(index.tsx, 16, 43)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) +>ReactNode : Symbol(ReactNode, Decl(index.tsx, 12, 3)) +} +declare namespace JSX { +>JSX : Symbol(JSX, Decl(index.tsx, 18, 1)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(index.tsx, 19, 23)) + + ul: React.DetailedHTMLProps, HTMLUListElement>; +>ul : Symbol(IntrinsicElements.ul, Decl(index.tsx, 20, 31)) +>React : Symbol(React, Decl(index.tsx, 6, 3), Decl(index.tsx, 25, 11)) +>DetailedHTMLProps : Symbol(React.DetailedHTMLProps, Decl(index.tsx, 8, 25)) +>React : Symbol(React, Decl(index.tsx, 6, 3), Decl(index.tsx, 25, 11)) +>HTMLAttributes : Symbol(React.HTMLAttributes, Decl(index.tsx, 9, 61)) +>HTMLUListElement : Symbol(HTMLUListElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>HTMLUListElement : Symbol(HTMLUListElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + + li: React.DetailedHTMLProps, HTMLLIElement>; +>li : Symbol(IntrinsicElements.li, Decl(index.tsx, 21, 90)) +>React : Symbol(React, Decl(index.tsx, 6, 3), Decl(index.tsx, 25, 11)) +>DetailedHTMLProps : Symbol(React.DetailedHTMLProps, Decl(index.tsx, 8, 25)) +>React : Symbol(React, Decl(index.tsx, 6, 3), Decl(index.tsx, 25, 11)) +>HTMLAttributes : Symbol(React.HTMLAttributes, Decl(index.tsx, 9, 61)) +>HTMLLIElement : Symbol(HTMLLIElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>HTMLLIElement : Symbol(HTMLLIElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) + } +} +declare var React: any; +>React : Symbol(React, Decl(index.tsx, 6, 3), Decl(index.tsx, 25, 11)) + +const Component = () => { +>Component : Symbol(Component, Decl(index.tsx, 27, 5)) + + const categories = ['Fruit', 'Vegetables']; +>categories : Symbol(categories, Decl(index.tsx, 28, 7)) + + return ( +
    +>ul : Symbol(JSX.IntrinsicElements.ul, Decl(index.tsx, 20, 31)) + +
  • All
  • +>li : Symbol(JSX.IntrinsicElements.li, Decl(index.tsx, 21, 90)) +>li : Symbol(JSX.IntrinsicElements.li, Decl(index.tsx, 21, 90)) + + {categories.map((category) => ( +>categories.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>categories : Symbol(categories, Decl(index.tsx, 28, 7)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --)) +>category : Symbol(category, Decl(index.tsx, 33, 23)) + +
  • {category}
  • // Error about 'key' only +>li : Symbol(JSX.IntrinsicElements.li, Decl(index.tsx, 21, 90)) +>key : Symbol(key, Decl(index.tsx, 34, 11)) +>category : Symbol(category, Decl(index.tsx, 33, 23)) +>category : Symbol(category, Decl(index.tsx, 33, 23)) +>li : Symbol(JSX.IntrinsicElements.li, Decl(index.tsx, 21, 90)) + + ))} +
+>ul : Symbol(JSX.IntrinsicElements.ul, Decl(index.tsx, 20, 31)) + + ); +}; + diff --git a/tests/baselines/reference/excessiveStackDepthFlatArray.types b/tests/baselines/reference/excessiveStackDepthFlatArray.types new file mode 100644 index 0000000000000..ae346a034fa67 --- /dev/null +++ b/tests/baselines/reference/excessiveStackDepthFlatArray.types @@ -0,0 +1,108 @@ +=== tests/cases/compiler/index.tsx === +interface MiddlewareArray extends Array {} +declare function configureStore(options: { middleware: MiddlewareArray }): void; +>configureStore : (options: { middleware: MiddlewareArray;}) => void +>options : { middleware: MiddlewareArray; } +>middleware : MiddlewareArray + +declare const defaultMiddleware: MiddlewareArray; +>defaultMiddleware : MiddlewareArray + +configureStore({ +>configureStore({ middleware: [...defaultMiddleware], // Should not error}) : void +>configureStore : (options: { middleware: MiddlewareArray; }) => void +>{ middleware: [...defaultMiddleware], // Should not error} : { middleware: any[]; } + + middleware: [...defaultMiddleware], // Should not error +>middleware : any[] +>[...defaultMiddleware] : any[] +>...defaultMiddleware : any +>defaultMiddleware : MiddlewareArray + +}); + +declare namespace React { + type DetailedHTMLProps, T> = E; +>DetailedHTMLProps : E + + interface HTMLAttributes { + children?: ReactNode; +>children : ReactNode + } + type ReactNode = ReactChild | ReactFragment | boolean | null | undefined; +>ReactNode : ReactNode +>null : null + + type ReactText = string | number; +>ReactText : ReactText + + type ReactChild = ReactText; +>ReactChild : ReactText + + type ReactFragment = {} | ReactNodeArray; +>ReactFragment : ReactFragment + + interface ReactNodeArray extends Array {} +} +declare namespace JSX { + interface IntrinsicElements { + ul: React.DetailedHTMLProps, HTMLUListElement>; +>ul : React.HTMLAttributes +>React : any +>React : any + + li: React.DetailedHTMLProps, HTMLLIElement>; +>li : React.HTMLAttributes +>React : any +>React : any + } +} +declare var React: any; +>React : any + +const Component = () => { +>Component : () => any +>() => { const categories = ['Fruit', 'Vegetables']; return (
  • All
  • {categories.map((category) => (
  • {category}
  • // Error about 'key' only ))}
);} : () => any + + const categories = ['Fruit', 'Vegetables']; +>categories : string[] +>['Fruit', 'Vegetables'] : string[] +>'Fruit' : "Fruit" +>'Vegetables' : "Vegetables" + + return ( +>(
  • All
  • {categories.map((category) => (
  • {category}
  • // Error about 'key' only ))}
) : any + +
    +>
    • All
    • {categories.map((category) => (
    • {category}
    • // Error about 'key' only ))}
    : any +>ul : any + +
  • All
  • +>
  • All
  • : any +>li : any +>li : any + + {categories.map((category) => ( +>categories.map((category) => (
  • {category}
  • // Error about 'key' only )) : any[] +>categories.map : (callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] +>categories : string[] +>map : (callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[] +>(category) => (
  • {category}
  • // Error about 'key' only ) : (category: string) => any +>category : string +>(
  • {category}
  • // Error about 'key' only ) : any + +
  • {category}
  • // Error about 'key' only +>
  • {category}
  • : any +>li : any +>key : string +>category : string +>category : string +>li : any + + ))} +
+>ul : any + + ); +}; + diff --git a/tests/cases/compiler/excessiveStackDepthFlatArray.ts b/tests/cases/compiler/excessiveStackDepthFlatArray.ts new file mode 100644 index 0000000000000..b8ad99e287d5a --- /dev/null +++ b/tests/cases/compiler/excessiveStackDepthFlatArray.ts @@ -0,0 +1,43 @@ +// @lib: es2019,dom +// @jsx: react + +// @Filename: index.tsx +interface MiddlewareArray extends Array {} +declare function configureStore(options: { middleware: MiddlewareArray }): void; + +declare const defaultMiddleware: MiddlewareArray; +configureStore({ + middleware: [...defaultMiddleware], // Should not error +}); + +declare namespace React { + type DetailedHTMLProps, T> = E; + interface HTMLAttributes { + children?: ReactNode; + } + type ReactNode = ReactChild | ReactFragment | boolean | null | undefined; + type ReactText = string | number; + type ReactChild = ReactText; + type ReactFragment = {} | ReactNodeArray; + interface ReactNodeArray extends Array {} +} +declare namespace JSX { + interface IntrinsicElements { + ul: React.DetailedHTMLProps, HTMLUListElement>; + li: React.DetailedHTMLProps, HTMLLIElement>; + } +} +declare var React: any; + +const Component = () => { + const categories = ['Fruit', 'Vegetables']; + + return ( +
    +
  • All
  • + {categories.map((category) => ( +
  • {category}
  • // Error about 'key' only + ))} +
+ ); +};