Defer union or intersection property type normalization (#31486)
* Defer union or intersection property type normalization * Accept moved span
This commit is contained in:
parent
38f3b05cb1
commit
e70f2af25d
|
@ -5921,7 +5921,20 @@ namespace ts {
|
|||
return anyType;
|
||||
}
|
||||
|
||||
function getTypeOfSymbolWithDeferredType(symbol: Symbol) {
|
||||
const links = getSymbolLinks(symbol);
|
||||
if (!links.type) {
|
||||
Debug.assertDefined(links.deferralParent);
|
||||
Debug.assertDefined(links.deferralConstituents);
|
||||
links.type = links.deferralParent!.flags & TypeFlags.Union ? getUnionType(links.deferralConstituents!) : getIntersectionType(links.deferralConstituents!);
|
||||
}
|
||||
return links.type;
|
||||
}
|
||||
|
||||
function getTypeOfSymbol(symbol: Symbol): Type {
|
||||
if (getCheckFlags(symbol) & CheckFlags.DeferredType) {
|
||||
return getTypeOfSymbolWithDeferredType(symbol);
|
||||
}
|
||||
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
|
||||
return getTypeOfInstantiatedSymbol(symbol);
|
||||
}
|
||||
|
@ -8061,7 +8074,15 @@ namespace ts {
|
|||
|
||||
result.declarations = declarations!;
|
||||
result.nameType = nameType;
|
||||
result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes);
|
||||
if (propTypes.length > 2) {
|
||||
// When `propTypes` has the potential to explode in size when normalized, defer normalization until absolutely needed
|
||||
result.checkFlags |= CheckFlags.DeferredType;
|
||||
result.deferralParent = containingType;
|
||||
result.deferralConstituents = propTypes;
|
||||
}
|
||||
else {
|
||||
result.type = isUnion ? getUnionType(propTypes) : getIntersectionType(propTypes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -12313,8 +12334,8 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
function isIgnoredJsxProperty(source: Type, sourceProp: Symbol, targetMemberType: Type | undefined) {
|
||||
return getObjectFlags(source) & ObjectFlags.JsxAttributes && !(isUnhyphenatedJsxName(sourceProp.escapedName) || targetMemberType);
|
||||
function isIgnoredJsxProperty(source: Type, sourceProp: Symbol) {
|
||||
return getObjectFlags(source) & ObjectFlags.JsxAttributes && !isUnhyphenatedJsxName(sourceProp.escapedName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13495,6 +13516,49 @@ namespace ts {
|
|||
return result || properties;
|
||||
}
|
||||
|
||||
function isPropertySymbolTypeRelated(sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary {
|
||||
const targetIsOptional = strictNullChecks && !!(getCheckFlags(targetProp) & CheckFlags.Partial);
|
||||
const source = getTypeOfSourceProperty(sourceProp);
|
||||
if (getCheckFlags(targetProp) & CheckFlags.DeferredType && !getSymbolLinks(targetProp).type) {
|
||||
// Rather than resolving (and normalizing) the type, relate constituent-by-constituent without performing normalization or seconadary passes
|
||||
const links = getSymbolLinks(targetProp);
|
||||
Debug.assertDefined(links.deferralParent);
|
||||
Debug.assertDefined(links.deferralConstituents);
|
||||
const unionParent = !!(links.deferralParent!.flags & TypeFlags.Union);
|
||||
let result = unionParent ? Ternary.False : Ternary.True;
|
||||
const targetTypes = links.deferralConstituents!;
|
||||
for (const targetType of targetTypes) {
|
||||
const related = isRelatedTo(source, targetType, /*reportErrors*/ false, /*headMessage*/ undefined, /*isIntersectionConstituent*/ !unionParent);
|
||||
if (!unionParent) {
|
||||
if (!related) {
|
||||
// Can't assign to a target individually - have to fallback to assigning to the _whole_ intersection (which forces normalization)
|
||||
return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors);
|
||||
}
|
||||
result &= related;
|
||||
}
|
||||
else {
|
||||
if (related) {
|
||||
return related;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unionParent && !result && targetIsOptional) {
|
||||
result = isRelatedTo(source, undefinedType);
|
||||
}
|
||||
if (unionParent && !result && reportErrors) {
|
||||
// The easiest way to get the right errors here is to un-defer (which may be costly)
|
||||
// If it turns out this is too costly too often, we can replicate the error handling logic within
|
||||
// typeRelatedToSomeType without the discriminatable type branch (as that requires a manifest union
|
||||
// type on which to hand discriminable properties, which we are expressly trying to avoid here)
|
||||
return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return isRelatedTo(source, addOptionality(getTypeOfSymbol(targetProp), targetIsOptional), reportErrors);
|
||||
}
|
||||
}
|
||||
|
||||
function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary {
|
||||
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
|
||||
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
|
||||
|
@ -13537,7 +13601,7 @@ namespace ts {
|
|||
return Ternary.False;
|
||||
}
|
||||
// If the target comes from a partial union prop, allow `undefined` in the target type
|
||||
const related = isRelatedTo(getTypeOfSourceProperty(sourceProp), addOptionality(getTypeOfSymbol(targetProp), !!(getCheckFlags(targetProp) & CheckFlags.Partial)), reportErrors);
|
||||
const related = isPropertySymbolTypeRelated(sourceProp, targetProp, getTypeOfSourceProperty, reportErrors);
|
||||
if (!related) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
|
||||
|
@ -13649,9 +13713,6 @@ namespace ts {
|
|||
if (!(targetProp.flags & SymbolFlags.Prototype)) {
|
||||
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
|
||||
if (sourceProp && sourceProp !== targetProp) {
|
||||
if (isIgnoredJsxProperty(source, sourceProp, getTypeOfSymbol(targetProp))) {
|
||||
continue;
|
||||
}
|
||||
const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors);
|
||||
if (!related) {
|
||||
return Ternary.False;
|
||||
|
@ -13797,7 +13858,7 @@ namespace ts {
|
|||
function eachPropertyRelatedTo(source: Type, target: Type, kind: IndexKind, reportErrors: boolean): Ternary {
|
||||
let result = Ternary.True;
|
||||
for (const prop of getPropertiesOfObjectType(source)) {
|
||||
if (isIgnoredJsxProperty(source, prop, /*targetMemberType*/ undefined)) {
|
||||
if (isIgnoredJsxProperty(source, prop)) {
|
||||
continue;
|
||||
}
|
||||
// Skip over symbol-named members
|
||||
|
|
|
@ -3752,6 +3752,8 @@ namespace ts {
|
|||
extendedContainers?: Symbol[]; // Containers (other than the parent) which this symbol is aliased in
|
||||
extendedContainersByFile?: Map<Symbol[]>; // Containers (other than the parent) which this symbol is aliased in
|
||||
variances?: VarianceFlags[]; // Alias symbol type argument variance cache
|
||||
deferralConstituents?: Type[]; // Calculated list of constituents for a deferred type
|
||||
deferralParent?: Type; // Source union/intersection of a deferred type
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
@ -3778,6 +3780,7 @@ namespace ts {
|
|||
ReverseMapped = 1 << 13, // Property of reverse-inferred homomorphic mapped type
|
||||
OptionalParameter = 1 << 14, // Optional parameter
|
||||
RestParameter = 1 << 15, // Rest parameter
|
||||
DeferredType = 1 << 16, // Calculation of the type of this symbol is deferred due to processing costs, should be fetched with `getTypeOfSymbolWithDeferredType`
|
||||
Synthetic = SyntheticProperty | SyntheticMethod,
|
||||
Discriminant = HasNonUniformType | HasLiteralType,
|
||||
Partial = ReadPartial | WritePartial
|
||||
|
|
|
@ -43,6 +43,28 @@ const de: D & E = {
|
|||
other: { g: 101 }
|
||||
}
|
||||
}
|
||||
|
||||
// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props
|
||||
interface F {
|
||||
nested: { doublyNested: { g: string; } }
|
||||
}
|
||||
|
||||
interface G {
|
||||
nested: { doublyNested: { h: string; } }
|
||||
}
|
||||
|
||||
const defg: D & E & F & G = {
|
||||
nested: {
|
||||
doublyNested: {
|
||||
d: 'yes',
|
||||
f: 'no',
|
||||
g: 'ok',
|
||||
h: 'affirmative'
|
||||
},
|
||||
different: { e: 12 },
|
||||
other: { g: 101 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [intersectionTypeMembers.js]
|
||||
|
@ -69,3 +91,15 @@ var de = {
|
|||
other: { g: 101 }
|
||||
}
|
||||
};
|
||||
var defg = {
|
||||
nested: {
|
||||
doublyNested: {
|
||||
d: 'yes',
|
||||
f: 'no',
|
||||
g: 'ok',
|
||||
h: 'affirmative'
|
||||
},
|
||||
different: { e: 12 },
|
||||
other: { g: 101 }
|
||||
}
|
||||
};
|
||||
|
|
|
@ -146,3 +146,58 @@ const de: D & E = {
|
|||
}
|
||||
}
|
||||
|
||||
// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props
|
||||
interface F {
|
||||
>F : Symbol(F, Decl(intersectionTypeMembers.ts, 43, 1))
|
||||
|
||||
nested: { doublyNested: { g: string; } }
|
||||
>nested : Symbol(F.nested, Decl(intersectionTypeMembers.ts, 46, 13))
|
||||
>doublyNested : Symbol(doublyNested, Decl(intersectionTypeMembers.ts, 47, 13))
|
||||
>g : Symbol(g, Decl(intersectionTypeMembers.ts, 47, 29))
|
||||
}
|
||||
|
||||
interface G {
|
||||
>G : Symbol(G, Decl(intersectionTypeMembers.ts, 48, 1))
|
||||
|
||||
nested: { doublyNested: { h: string; } }
|
||||
>nested : Symbol(G.nested, Decl(intersectionTypeMembers.ts, 50, 13))
|
||||
>doublyNested : Symbol(doublyNested, Decl(intersectionTypeMembers.ts, 51, 13))
|
||||
>h : Symbol(h, Decl(intersectionTypeMembers.ts, 51, 29))
|
||||
}
|
||||
|
||||
const defg: D & E & F & G = {
|
||||
>defg : Symbol(defg, Decl(intersectionTypeMembers.ts, 54, 5))
|
||||
>D : Symbol(D, Decl(intersectionTypeMembers.ts, 26, 14))
|
||||
>E : Symbol(E, Decl(intersectionTypeMembers.ts, 30, 1))
|
||||
>F : Symbol(F, Decl(intersectionTypeMembers.ts, 43, 1))
|
||||
>G : Symbol(G, Decl(intersectionTypeMembers.ts, 48, 1))
|
||||
|
||||
nested: {
|
||||
>nested : Symbol(nested, Decl(intersectionTypeMembers.ts, 54, 29))
|
||||
|
||||
doublyNested: {
|
||||
>doublyNested : Symbol(doublyNested, Decl(intersectionTypeMembers.ts, 55, 13))
|
||||
|
||||
d: 'yes',
|
||||
>d : Symbol(d, Decl(intersectionTypeMembers.ts, 56, 23))
|
||||
|
||||
f: 'no',
|
||||
>f : Symbol(f, Decl(intersectionTypeMembers.ts, 57, 21))
|
||||
|
||||
g: 'ok',
|
||||
>g : Symbol(g, Decl(intersectionTypeMembers.ts, 58, 20))
|
||||
|
||||
h: 'affirmative'
|
||||
>h : Symbol(h, Decl(intersectionTypeMembers.ts, 59, 20))
|
||||
|
||||
},
|
||||
different: { e: 12 },
|
||||
>different : Symbol(different, Decl(intersectionTypeMembers.ts, 61, 10))
|
||||
>e : Symbol(e, Decl(intersectionTypeMembers.ts, 62, 20))
|
||||
|
||||
other: { g: 101 }
|
||||
>other : Symbol(other, Decl(intersectionTypeMembers.ts, 62, 29))
|
||||
>g : Symbol(g, Decl(intersectionTypeMembers.ts, 63, 16))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,3 +148,61 @@ const de: D & E = {
|
|||
}
|
||||
}
|
||||
|
||||
// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props
|
||||
interface F {
|
||||
nested: { doublyNested: { g: string; } }
|
||||
>nested : { doublyNested: { g: string; }; }
|
||||
>doublyNested : { g: string; }
|
||||
>g : string
|
||||
}
|
||||
|
||||
interface G {
|
||||
nested: { doublyNested: { h: string; } }
|
||||
>nested : { doublyNested: { h: string; }; }
|
||||
>doublyNested : { h: string; }
|
||||
>h : string
|
||||
}
|
||||
|
||||
const defg: D & E & F & G = {
|
||||
>defg : D & E & F & G
|
||||
>{ nested: { doublyNested: { d: 'yes', f: 'no', g: 'ok', h: 'affirmative' }, different: { e: 12 }, other: { g: 101 } }} : { nested: { doublyNested: { d: string; f: string; g: string; h: string; }; different: { e: number; }; other: { g: number; }; }; }
|
||||
|
||||
nested: {
|
||||
>nested : { doublyNested: { d: string; f: string; g: string; h: string; }; different: { e: number; }; other: { g: number; }; }
|
||||
>{ doublyNested: { d: 'yes', f: 'no', g: 'ok', h: 'affirmative' }, different: { e: 12 }, other: { g: 101 } } : { doublyNested: { d: string; f: string; g: string; h: string; }; different: { e: number; }; other: { g: number; }; }
|
||||
|
||||
doublyNested: {
|
||||
>doublyNested : { d: string; f: string; g: string; h: string; }
|
||||
>{ d: 'yes', f: 'no', g: 'ok', h: 'affirmative' } : { d: string; f: string; g: string; h: string; }
|
||||
|
||||
d: 'yes',
|
||||
>d : string
|
||||
>'yes' : "yes"
|
||||
|
||||
f: 'no',
|
||||
>f : string
|
||||
>'no' : "no"
|
||||
|
||||
g: 'ok',
|
||||
>g : string
|
||||
>'ok' : "ok"
|
||||
|
||||
h: 'affirmative'
|
||||
>h : string
|
||||
>'affirmative' : "affirmative"
|
||||
|
||||
},
|
||||
different: { e: 12 },
|
||||
>different : { e: number; }
|
||||
>{ e: 12 } : { e: number; }
|
||||
>e : number
|
||||
>12 : 12
|
||||
|
||||
other: { g: 101 }
|
||||
>other : { g: number; }
|
||||
>{ g: 101 } : { g: number; }
|
||||
>g : number
|
||||
>101 : 101
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,14): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS7006: Parameter 'x' implicitly has an 'any' type.
|
||||
tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS2590: Expression produces a union type that is too complex to represent.
|
||||
|
||||
|
||||
==== tests/cases/compiler/normalizedIntersectionTooComplex.ts (2 errors) ====
|
||||
|
@ -39,8 +39,8 @@ tests/cases/compiler/normalizedIntersectionTooComplex.ts(36,40): error TS7006: P
|
|||
declare var all: keyof Big;
|
||||
const ctor = getCtor(all);
|
||||
const comp = ctor({ common: "ok", ref: x => console.log(x) });
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2590: Expression produces a union type that is too complex to represent.
|
||||
~
|
||||
!!! error TS7006: Parameter 'x' implicitly has an 'any' type.
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2590: Expression produces a union type that is too complex to represent.
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
//// [reactTagNameComponentWithPropsNoOOM.tsx]
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
|
||||
const classes = "";
|
||||
const rest: {} = {};
|
||||
const children: any[] = [];
|
||||
<Tag className={classes} {...rest}>
|
||||
{children}
|
||||
</Tag>
|
||||
|
||||
//// [reactTagNameComponentWithPropsNoOOM.js]
|
||||
"use strict";
|
||||
/// <reference path="react16.d.ts" />
|
||||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
exports.__esModule = true;
|
||||
var React = require("react");
|
||||
var classes = "";
|
||||
var rest = {};
|
||||
var children = [];
|
||||
React.createElement(Tag, __assign({ className: classes }, rest), children);
|
|
@ -0,0 +1,32 @@
|
|||
=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 2, 6))
|
||||
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 3, 13))
|
||||
>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 2, 6))
|
||||
>ReactHTML : Symbol(React.ReactHTML, Decl(react16.d.ts, 2089, 9))
|
||||
|
||||
const classes = "";
|
||||
>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 5, 5))
|
||||
|
||||
const rest: {} = {};
|
||||
>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 6, 5))
|
||||
|
||||
const children: any[] = [];
|
||||
>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 7, 5))
|
||||
|
||||
<Tag className={classes} {...rest}>
|
||||
>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 3, 13))
|
||||
>className : Symbol(className, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 8, 4))
|
||||
>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 5, 5))
|
||||
>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 6, 5))
|
||||
|
||||
{children}
|
||||
>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 7, 5))
|
||||
|
||||
</Tag>
|
||||
>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM.tsx, 3, 13))
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
>React : typeof React
|
||||
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview"
|
||||
>React : any
|
||||
|
||||
const classes = "";
|
||||
>classes : ""
|
||||
>"" : ""
|
||||
|
||||
const rest: {} = {};
|
||||
>rest : {}
|
||||
>{} : {}
|
||||
|
||||
const children: any[] = [];
|
||||
>children : any[]
|
||||
>[] : never[]
|
||||
|
||||
<Tag className={classes} {...rest}>
|
||||
><Tag className={classes} {...rest}>{children}</Tag> : JSX.Element
|
||||
>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview"
|
||||
>className : string
|
||||
>classes : ""
|
||||
>rest : {}
|
||||
|
||||
{children}
|
||||
>children : any[]
|
||||
|
||||
</Tag>
|
||||
>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview"
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
//// [reactTagNameComponentWithPropsNoOOM2.tsx]
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
|
||||
const classes = "";
|
||||
const rest: React.HTMLAttributes<HTMLElement> = {};
|
||||
const children: any[] = [];
|
||||
<Tag className={classes} {...rest}>
|
||||
{children}
|
||||
</Tag>
|
||||
|
||||
//// [reactTagNameComponentWithPropsNoOOM2.js]
|
||||
"use strict";
|
||||
/// <reference path="react16.d.ts" />
|
||||
var __assign = (this && this.__assign) || function () {
|
||||
__assign = Object.assign || function(t) {
|
||||
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
||||
s = arguments[i];
|
||||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
||||
t[p] = s[p];
|
||||
}
|
||||
return t;
|
||||
};
|
||||
return __assign.apply(this, arguments);
|
||||
};
|
||||
exports.__esModule = true;
|
||||
var React = require("react");
|
||||
var classes = "";
|
||||
var rest = {};
|
||||
var children = [];
|
||||
React.createElement(Tag, __assign({ className: classes }, rest), children);
|
|
@ -0,0 +1,35 @@
|
|||
=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM2.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 2, 6))
|
||||
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 3, 13))
|
||||
>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 2, 6))
|
||||
>ReactHTML : Symbol(React.ReactHTML, Decl(react16.d.ts, 2089, 9))
|
||||
|
||||
const classes = "";
|
||||
>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 5, 5))
|
||||
|
||||
const rest: React.HTMLAttributes<HTMLElement> = {};
|
||||
>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 6, 5))
|
||||
>React : Symbol(React, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 2, 6))
|
||||
>HTMLAttributes : Symbol(React.HTMLAttributes, Decl(react16.d.ts, 1048, 9), Decl(react16.d.ts, 1105, 9))
|
||||
>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
|
||||
const children: any[] = [];
|
||||
>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 7, 5))
|
||||
|
||||
<Tag className={classes} {...rest}>
|
||||
>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 3, 13))
|
||||
>className : Symbol(className, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 8, 4))
|
||||
>classes : Symbol(classes, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 5, 5))
|
||||
>rest : Symbol(rest, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 6, 5))
|
||||
|
||||
{children}
|
||||
>children : Symbol(children, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 7, 5))
|
||||
|
||||
</Tag>
|
||||
>Tag : Symbol(Tag, Decl(reactTagNameComponentWithPropsNoOOM2.tsx, 3, 13))
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
=== tests/cases/compiler/reactTagNameComponentWithPropsNoOOM2.tsx ===
|
||||
/// <reference path="react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
>React : typeof React
|
||||
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview"
|
||||
>React : any
|
||||
|
||||
const classes = "";
|
||||
>classes : ""
|
||||
>"" : ""
|
||||
|
||||
const rest: React.HTMLAttributes<HTMLElement> = {};
|
||||
>rest : React.HTMLAttributes<HTMLElement>
|
||||
>React : any
|
||||
>{} : {}
|
||||
|
||||
const children: any[] = [];
|
||||
>children : any[]
|
||||
>[] : never[]
|
||||
|
||||
<Tag className={classes} {...rest}>
|
||||
><Tag className={classes} {...rest}>{children}</Tag> : JSX.Element
|
||||
>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview"
|
||||
>className : string
|
||||
>classes : ""
|
||||
>rest : React.HTMLAttributes<HTMLElement>
|
||||
|
||||
{children}
|
||||
>children : any[]
|
||||
|
||||
</Tag>
|
||||
>Tag : "object" | "time" | "link" | "menu" | "dialog" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | "caption" | "cite" | "code" | "col" | "colgroup" | "data" | "datalist" | "dd" | "del" | "details" | "dfn" | "div" | "dl" | "dt" | "em" | "embed" | "fieldset" | "figcaption" | "figure" | "footer" | "form" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "head" | "header" | "hgroup" | "hr" | "html" | "i" | "iframe" | "img" | "input" | "ins" | "kbd" | "keygen" | "label" | "legend" | "li" | "main" | "map" | "mark" | "menuitem" | "meta" | "meter" | "nav" | "noscript" | "ol" | "optgroup" | "option" | "output" | "p" | "param" | "picture" | "pre" | "progress" | "q" | "rp" | "rt" | "ruby" | "s" | "samp" | "script" | "section" | "select" | "small" | "source" | "span" | "strong" | "style" | "sub" | "summary" | "sup" | "table" | "tbody" | "td" | "textarea" | "tfoot" | "th" | "thead" | "title" | "tr" | "track" | "u" | "ul" | "var" | "video" | "wbr" | "webview"
|
||||
|
13
tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx
Normal file
13
tests/cases/compiler/reactTagNameComponentWithPropsNoOOM.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
// @jsx: react
|
||||
// @strict: true
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
|
||||
const classes = "";
|
||||
const rest: {} = {};
|
||||
const children: any[] = [];
|
||||
<Tag className={classes} {...rest}>
|
||||
{children}
|
||||
</Tag>
|
|
@ -0,0 +1,13 @@
|
|||
// @jsx: react
|
||||
// @strict: true
|
||||
/// <reference path="/.lib/react16.d.ts" />
|
||||
|
||||
import * as React from "react";
|
||||
declare const Tag: keyof React.ReactHTML;
|
||||
|
||||
const classes = "";
|
||||
const rest: React.HTMLAttributes<HTMLElement> = {};
|
||||
const children: any[] = [];
|
||||
<Tag className={classes} {...rest}>
|
||||
{children}
|
||||
</Tag>
|
|
@ -42,3 +42,25 @@ const de: D & E = {
|
|||
other: { g: 101 }
|
||||
}
|
||||
}
|
||||
|
||||
// Additional test case with >2 doubly nested members so fix for #31441 is tested w/ excess props
|
||||
interface F {
|
||||
nested: { doublyNested: { g: string; } }
|
||||
}
|
||||
|
||||
interface G {
|
||||
nested: { doublyNested: { h: string; } }
|
||||
}
|
||||
|
||||
const defg: D & E & F & G = {
|
||||
nested: {
|
||||
doublyNested: {
|
||||
d: 'yes',
|
||||
f: 'no',
|
||||
g: 'ok',
|
||||
h: 'affirmative'
|
||||
},
|
||||
different: { e: 12 },
|
||||
other: { g: 101 }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue