mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
feat(36908): add 'property overwritten by spread' error for jsx attributes. add related span for conflicting declaration in spread (#37329)
This commit is contained in:
+20
-13
@@ -22684,8 +22684,8 @@ namespace ts {
|
||||
// Grammar checking
|
||||
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
|
||||
|
||||
let propertiesTable: SymbolTable;
|
||||
const allPropertiesTable = createSymbolTable();
|
||||
const allPropertiesTable = strictNullChecks ? createSymbolTable() : undefined;
|
||||
let propertiesTable = createSymbolTable();
|
||||
let propertiesArray: Symbol[] = [];
|
||||
let spread: Type = emptyObjectType;
|
||||
|
||||
@@ -22701,7 +22701,6 @@ namespace ts {
|
||||
let patternWithComputedProperties = false;
|
||||
let hasComputedStringProperty = false;
|
||||
let hasComputedNumberProperty = false;
|
||||
propertiesTable = createSymbolTable();
|
||||
|
||||
let offset = 0;
|
||||
for (let i = 0; i < node.properties.length; i++) {
|
||||
@@ -22767,7 +22766,7 @@ namespace ts {
|
||||
prop.type = type;
|
||||
prop.target = member;
|
||||
member = prop;
|
||||
allPropertiesTable.set(prop.escapedName, prop);
|
||||
allPropertiesTable?.set(prop.escapedName, prop);
|
||||
}
|
||||
else if (memberDecl.kind === SyntaxKind.SpreadAssignment) {
|
||||
if (languageVersion < ScriptTarget.ES2015) {
|
||||
@@ -22785,16 +22784,9 @@ namespace ts {
|
||||
error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
|
||||
return errorType;
|
||||
}
|
||||
for (const right of getPropertiesOfType(type)) {
|
||||
const rightType = getTypeOfSymbol(right);
|
||||
const left = allPropertiesTable.get(right.escapedName);
|
||||
if (strictNullChecks &&
|
||||
left &&
|
||||
!maybeTypeOfKind(rightType, TypeFlags.Nullable)) {
|
||||
error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName));
|
||||
}
|
||||
if (allPropertiesTable) {
|
||||
checkSpreadPropOverrides(type, allPropertiesTable, memberDecl);
|
||||
}
|
||||
|
||||
spread = getSpreadType(spread, type, node.symbol, objectFlags, inConstContext);
|
||||
offset = i + 1;
|
||||
continue;
|
||||
@@ -22965,6 +22957,7 @@ namespace ts {
|
||||
*/
|
||||
function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, checkMode: CheckMode | undefined) {
|
||||
const attributes = openingLikeElement.attributes;
|
||||
const allAttributesTable = strictNullChecks ? createSymbolTable() : undefined;
|
||||
let attributesTable = createSymbolTable();
|
||||
let spread: Type = emptyJsxObjectType;
|
||||
let hasSpreadAnyType = false;
|
||||
@@ -22988,6 +22981,7 @@ namespace ts {
|
||||
attributeSymbol.type = exprType;
|
||||
attributeSymbol.target = member;
|
||||
attributesTable.set(attributeSymbol.escapedName, attributeSymbol);
|
||||
allAttributesTable?.set(attributeSymbol.escapedName, attributeSymbol);
|
||||
if (attributeDecl.name.escapedText === jsxChildrenPropertyName) {
|
||||
explicitlySpecifyChildrenAttribute = true;
|
||||
}
|
||||
@@ -23004,6 +22998,9 @@ namespace ts {
|
||||
}
|
||||
if (isValidSpreadType(exprType)) {
|
||||
spread = getSpreadType(spread, exprType, attributes.symbol, objectFlags, /*readonly*/ false);
|
||||
if (allAttributesTable) {
|
||||
checkSpreadPropOverrides(exprType, allAttributesTable, attributeDecl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType;
|
||||
@@ -23088,6 +23085,16 @@ namespace ts {
|
||||
return childrenTypes;
|
||||
}
|
||||
|
||||
function checkSpreadPropOverrides(type: Type, props: SymbolTable, spread: SpreadAssignment | JsxSpreadAttribute) {
|
||||
for (const right of getPropertiesOfType(type)) {
|
||||
const left = props.get(right.escapedName);
|
||||
if (left && !maybeTypeOfKind(getTypeOfSymbol(right), TypeFlags.Nullable)) {
|
||||
const diagnostic = error(left.valueDeclaration, Diagnostics._0_is_specified_more_than_once_so_this_usage_will_be_overwritten, unescapeLeadingUnderscores(left.escapedName));
|
||||
addRelatedInfo(diagnostic, createDiagnosticForNode(spread, Diagnostics.This_spread_always_overwrites_this_property));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check attributes property of opening-like element. This function is called during chooseOverload to get call signature of a JSX opening-like element.
|
||||
* (See "checkApplicableSignatureForJsxOpeningLikeElement" for how the function is used)
|
||||
|
||||
@@ -2907,6 +2907,10 @@
|
||||
"category": "Error",
|
||||
"code": 2784
|
||||
},
|
||||
"This spread always overwrites this property.": {
|
||||
"category": "Error",
|
||||
"code": 2785
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
error TS2318: Cannot find global type 'CallableFunction'.
|
||||
error TS2318: Cannot find global type 'NewableFunction'.
|
||||
tests/cases/conformance/jsx/file.tsx(19,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/jsx/file.tsx(20,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/jsx/file.tsx(20,23): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/jsx/file.tsx(21,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/jsx/file.tsx(21,23): error TS2783: 'd' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/jsx/file.tsx(22,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/jsx/file.tsx(22,17): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/jsx/file.tsx(22,23): error TS2783: 'd' is specified more than once, so this usage will be overwritten.
|
||||
|
||||
|
||||
!!! error TS2318: Cannot find global type 'CallableFunction'.
|
||||
!!! error TS2318: Cannot find global type 'NewableFunction'.
|
||||
==== tests/cases/conformance/jsx/file.tsx (8 errors) ====
|
||||
import React = require('react');
|
||||
|
||||
interface Props {
|
||||
a: number;
|
||||
b: number;
|
||||
c?: number;
|
||||
d?: number;
|
||||
}
|
||||
|
||||
|
||||
const props: Props = { a: 1, b: 1 };
|
||||
const Foo = (props: Props) => <div>{ props.a }</div>;
|
||||
|
||||
// ok
|
||||
const a1 = <Foo {...props}></Foo>;
|
||||
const a2 = <Foo d={1} {...props}></Foo>;
|
||||
|
||||
// error
|
||||
const b1 = <Foo a={1} {...props}></Foo>;
|
||||
~~~~~
|
||||
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:19:23: This spread always overwrites this property.
|
||||
const b2 = <Foo a={1} b={2} {...props}></Foo>;
|
||||
~~~~~
|
||||
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:20:29: This spread always overwrites this property.
|
||||
~~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:20:29: This spread always overwrites this property.
|
||||
const b3 = <Foo a={1} d={1} {...props} {...{ d: 1 }}></Foo>;
|
||||
~~~~~
|
||||
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:21:29: This spread always overwrites this property.
|
||||
~~~~~
|
||||
!!! error TS2783: 'd' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:21:40: This spread always overwrites this property.
|
||||
const b4 = <Foo a={1} d={1} {...props} {...{ a: 1, d: 1 }}></Foo>;
|
||||
~~~~~
|
||||
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:22:29: This spread always overwrites this property.
|
||||
~~~~~
|
||||
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:22:40: This spread always overwrites this property.
|
||||
~~~~~
|
||||
!!! error TS2783: 'd' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/jsx/file.tsx:22:40: This spread always overwrites this property.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
//// [file.tsx]
|
||||
import React = require('react');
|
||||
|
||||
interface Props {
|
||||
a: number;
|
||||
b: number;
|
||||
c?: number;
|
||||
d?: number;
|
||||
}
|
||||
|
||||
|
||||
const props: Props = { a: 1, b: 1 };
|
||||
const Foo = (props: Props) => <div>{ props.a }</div>;
|
||||
|
||||
// ok
|
||||
const a1 = <Foo {...props}></Foo>;
|
||||
const a2 = <Foo d={1} {...props}></Foo>;
|
||||
|
||||
// error
|
||||
const b1 = <Foo a={1} {...props}></Foo>;
|
||||
const b2 = <Foo a={1} b={2} {...props}></Foo>;
|
||||
const b3 = <Foo a={1} d={1} {...props} {...{ d: 1 }}></Foo>;
|
||||
const b4 = <Foo a={1} d={1} {...props} {...{ a: 1, d: 1 }}></Foo>;
|
||||
|
||||
|
||||
//// [file.jsx]
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
var React = require("react");
|
||||
var props = { a: 1, b: 1 };
|
||||
var Foo = function (props) { return <div>{props.a}</div>; };
|
||||
// ok
|
||||
var a1 = <Foo {...props}></Foo>;
|
||||
var a2 = <Foo d={1} {...props}></Foo>;
|
||||
// error
|
||||
var b1 = <Foo a={1} {...props}></Foo>;
|
||||
var b2 = <Foo a={1} b={2} {...props}></Foo>;
|
||||
var b3 = <Foo a={1} d={1} {...props} {...{ d: 1 }}></Foo>;
|
||||
var b4 = <Foo a={1} d={1} {...props} {...{ a: 1, d: 1 }}></Foo>;
|
||||
@@ -0,0 +1,86 @@
|
||||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
import React = require('react');
|
||||
>React : Symbol(React, Decl(file.tsx, 0, 0))
|
||||
|
||||
interface Props {
|
||||
>Props : Symbol(Props, Decl(file.tsx, 0, 32))
|
||||
|
||||
a: number;
|
||||
>a : Symbol(Props.a, Decl(file.tsx, 2, 17))
|
||||
|
||||
b: number;
|
||||
>b : Symbol(Props.b, Decl(file.tsx, 3, 14))
|
||||
|
||||
c?: number;
|
||||
>c : Symbol(Props.c, Decl(file.tsx, 4, 14))
|
||||
|
||||
d?: number;
|
||||
>d : Symbol(Props.d, Decl(file.tsx, 5, 15))
|
||||
}
|
||||
|
||||
|
||||
const props: Props = { a: 1, b: 1 };
|
||||
>props : Symbol(props, Decl(file.tsx, 10, 5))
|
||||
>Props : Symbol(Props, Decl(file.tsx, 0, 32))
|
||||
>a : Symbol(a, Decl(file.tsx, 10, 22))
|
||||
>b : Symbol(b, Decl(file.tsx, 10, 28))
|
||||
|
||||
const Foo = (props: Props) => <div>{ props.a }</div>;
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
>props : Symbol(props, Decl(file.tsx, 11, 13))
|
||||
>Props : Symbol(Props, Decl(file.tsx, 0, 32))
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
|
||||
>props.a : Symbol(Props.a, Decl(file.tsx, 2, 17))
|
||||
>props : Symbol(props, Decl(file.tsx, 11, 13))
|
||||
>a : Symbol(Props.a, Decl(file.tsx, 2, 17))
|
||||
>div : Symbol(JSX.IntrinsicElements.div, Decl(react.d.ts, 2400, 45))
|
||||
|
||||
// ok
|
||||
const a1 = <Foo {...props}></Foo>;
|
||||
>a1 : Symbol(a1, Decl(file.tsx, 14, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
>props : Symbol(props, Decl(file.tsx, 10, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
|
||||
const a2 = <Foo d={1} {...props}></Foo>;
|
||||
>a2 : Symbol(a2, Decl(file.tsx, 15, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
>d : Symbol(d, Decl(file.tsx, 15, 15))
|
||||
>props : Symbol(props, Decl(file.tsx, 10, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
|
||||
// error
|
||||
const b1 = <Foo a={1} {...props}></Foo>;
|
||||
>b1 : Symbol(b1, Decl(file.tsx, 18, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
>a : Symbol(a, Decl(file.tsx, 18, 15))
|
||||
>props : Symbol(props, Decl(file.tsx, 10, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
|
||||
const b2 = <Foo a={1} b={2} {...props}></Foo>;
|
||||
>b2 : Symbol(b2, Decl(file.tsx, 19, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
>a : Symbol(a, Decl(file.tsx, 19, 15))
|
||||
>b : Symbol(b, Decl(file.tsx, 19, 21))
|
||||
>props : Symbol(props, Decl(file.tsx, 10, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
|
||||
const b3 = <Foo a={1} d={1} {...props} {...{ d: 1 }}></Foo>;
|
||||
>b3 : Symbol(b3, Decl(file.tsx, 20, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
>a : Symbol(a, Decl(file.tsx, 20, 15))
|
||||
>d : Symbol(d, Decl(file.tsx, 20, 21))
|
||||
>props : Symbol(props, Decl(file.tsx, 10, 5))
|
||||
>d : Symbol(d, Decl(file.tsx, 20, 44))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
|
||||
const b4 = <Foo a={1} d={1} {...props} {...{ a: 1, d: 1 }}></Foo>;
|
||||
>b4 : Symbol(b4, Decl(file.tsx, 21, 5))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
>a : Symbol(a, Decl(file.tsx, 21, 15))
|
||||
>d : Symbol(d, Decl(file.tsx, 21, 21))
|
||||
>props : Symbol(props, Decl(file.tsx, 10, 5))
|
||||
>a : Symbol(a, Decl(file.tsx, 21, 44))
|
||||
>d : Symbol(d, Decl(file.tsx, 21, 50))
|
||||
>Foo : Symbol(Foo, Decl(file.tsx, 11, 5))
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
=== tests/cases/conformance/jsx/file.tsx ===
|
||||
import React = require('react');
|
||||
>React : typeof React
|
||||
|
||||
interface Props {
|
||||
a: number;
|
||||
>a : number
|
||||
|
||||
b: number;
|
||||
>b : number
|
||||
|
||||
c?: number;
|
||||
>c : number | undefined
|
||||
|
||||
d?: number;
|
||||
>d : number | undefined
|
||||
}
|
||||
|
||||
|
||||
const props: Props = { a: 1, b: 1 };
|
||||
>props : Props
|
||||
>{ a: 1, b: 1 } : { a: number; b: number; }
|
||||
>a : number
|
||||
>1 : 1
|
||||
>b : number
|
||||
>1 : 1
|
||||
|
||||
const Foo = (props: Props) => <div>{ props.a }</div>;
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
>(props: Props) => <div>{ props.a }</div> : (props: Props) => JSX.Element
|
||||
>props : Props
|
||||
><div>{ props.a }</div> : JSX.Element
|
||||
>div : any
|
||||
>props.a : number
|
||||
>props : Props
|
||||
>a : number
|
||||
>div : any
|
||||
|
||||
// ok
|
||||
const a1 = <Foo {...props}></Foo>;
|
||||
>a1 : JSX.Element
|
||||
><Foo {...props}></Foo> : JSX.Element
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
>props : Props
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
|
||||
const a2 = <Foo d={1} {...props}></Foo>;
|
||||
>a2 : JSX.Element
|
||||
><Foo d={1} {...props}></Foo> : JSX.Element
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
>d : number
|
||||
>1 : 1
|
||||
>props : Props
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
|
||||
// error
|
||||
const b1 = <Foo a={1} {...props}></Foo>;
|
||||
>b1 : JSX.Element
|
||||
><Foo a={1} {...props}></Foo> : JSX.Element
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
>a : number
|
||||
>1 : 1
|
||||
>props : Props
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
|
||||
const b2 = <Foo a={1} b={2} {...props}></Foo>;
|
||||
>b2 : JSX.Element
|
||||
><Foo a={1} b={2} {...props}></Foo> : JSX.Element
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
>a : number
|
||||
>1 : 1
|
||||
>b : number
|
||||
>2 : 2
|
||||
>props : Props
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
|
||||
const b3 = <Foo a={1} d={1} {...props} {...{ d: 1 }}></Foo>;
|
||||
>b3 : JSX.Element
|
||||
><Foo a={1} d={1} {...props} {...{ d: 1 }}></Foo> : JSX.Element
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
>a : number
|
||||
>1 : 1
|
||||
>d : number
|
||||
>1 : 1
|
||||
>props : Props
|
||||
>{ d: 1 } : { d: number; }
|
||||
>d : number
|
||||
>1 : 1
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
|
||||
const b4 = <Foo a={1} d={1} {...props} {...{ a: 1, d: 1 }}></Foo>;
|
||||
>b4 : JSX.Element
|
||||
><Foo a={1} d={1} {...props} {...{ a: 1, d: 1 }}></Foo> : JSX.Element
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
>a : number
|
||||
>1 : 1
|
||||
>d : number
|
||||
>1 : 1
|
||||
>props : Props
|
||||
>{ a: 1, d: 1 } : { a: number; d: number; }
|
||||
>a : number
|
||||
>1 : 1
|
||||
>d : number
|
||||
>1 : 1
|
||||
>Foo : (props: Props) => JSX.Element
|
||||
|
||||
@@ -10,6 +10,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS230
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'.
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,7): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,7): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,7): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,14): error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(41,53): error TS2783: 'd' is specified more than once, so this usage will be overwritten.
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(43,7): error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
@@ -26,7 +27,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(69,9): error TS2339
|
||||
tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS2339: Property 'a' does not exist on type '{}'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (22 errors) ====
|
||||
==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (23 errors) ====
|
||||
let o = { a: 1, b: 'no' }
|
||||
|
||||
/// private propagates
|
||||
@@ -70,6 +71,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS233
|
||||
let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' }
|
||||
~~~~~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:28:30: This spread always overwrites this property.
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'b'.
|
||||
~
|
||||
@@ -80,6 +82,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS233
|
||||
{ b: 'ignored', ...o }
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:32:21: This spread always overwrites this property.
|
||||
|
||||
let o3 = { a: 1, b: 'no' }
|
||||
let o4 = { b: 'yes', c: true }
|
||||
@@ -87,22 +90,30 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(74,11): error TS233
|
||||
{ b: 'ok', ...o3, ...o4 }
|
||||
~~~~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:37:16: This spread always overwrites this property.
|
||||
~~~~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:37:23: This spread always overwrites this property.
|
||||
let combinedMid: { a: number, b: string, c: boolean } =
|
||||
{ ...o3, b: 'ok', ...o4 }
|
||||
~~~~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:39:23: This spread always overwrites this property.
|
||||
let combinedNested: { a: number, b: boolean, c: string, d: string } =
|
||||
{ ...{ a: 4, ...{ b: false, c: 'overriden' } }, d: 'actually new', ...{ a: 5, d: 'maybe new' } }
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2783: 'd' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:41:72: This spread always overwrites this property.
|
||||
let changeTypeBefore: { a: number, b: string } =
|
||||
{ a: 'wrong type?', ...o3 };
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS2783: 'a' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:43:25: This spread always overwrites this property.
|
||||
let computedMiddle: { a: number, b: string, c: boolean, "in the middle": number } =
|
||||
{ ...o3, ['in the middle']: 13, b: 'maybe?', ...o4 }
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadNegative.ts:45:50: This spread always overwrites this property.
|
||||
|
||||
// primitives are not allowed, except for falsy ones
|
||||
let spreadNum = { ...12 };
|
||||
|
||||
@@ -6,4 +6,5 @@ tests/cases/conformance/types/spread/objectSpreadSetonlyAccessor.ts(2,34): error
|
||||
const o2: { foo: undefined } = { foo: 1, ... { set foo(_v: number) { } } }
|
||||
~~~~~~
|
||||
!!! error TS2783: 'foo' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/objectSpreadSetonlyAccessor.ts:2:42: This spread always overwrites this property.
|
||||
|
||||
@@ -9,6 +9,7 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): e
|
||||
var unused1 = { b: 1, ...ab } // error
|
||||
~~~~
|
||||
!!! error TS2783: 'b' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:3:23: This spread always overwrites this property.
|
||||
var unused2 = { ...ab, ...ab } // ok, overwritten error doesn't apply to spreads
|
||||
var unused3 = { b: 1, ...abq } // ok, abq might have b: undefined
|
||||
var unused4 = { ...ab, b: 1 } // ok, we don't care that b in ab is overwritten
|
||||
@@ -23,6 +24,7 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): e
|
||||
return { x: 1, ...obj } // error
|
||||
~~~~
|
||||
!!! error TS2783: 'x' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:15:20: This spread always overwrites this property.
|
||||
}
|
||||
function i(b: boolean, t: { command: string, ok: string }) {
|
||||
return { command: "hi", ...(b ? t : {}) } // ok
|
||||
@@ -34,5 +36,6 @@ tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts(24,14): e
|
||||
return { command: "hi", ...{ spoiler: true }, spoiler2: true, ...t } // error
|
||||
~~~~~~~~~~~~~
|
||||
!!! error TS2783: 'command' is specified more than once, so this usage will be overwritten.
|
||||
!!! related TS2785 tests/cases/conformance/types/spread/spreadOverwritesPropertyStrict.ts:24:67: This spread always overwrites this property.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// @filename: file.tsx
|
||||
// @jsx: preserve
|
||||
// @strict: true
|
||||
// @noLib: true
|
||||
// @skipLibCheck: true
|
||||
// @libFiles: react.d.ts,lib.d.ts
|
||||
|
||||
import React = require('react');
|
||||
|
||||
interface Props {
|
||||
a: number;
|
||||
b: number;
|
||||
c?: number;
|
||||
d?: number;
|
||||
}
|
||||
|
||||
|
||||
const props: Props = { a: 1, b: 1 };
|
||||
const Foo = (props: Props) => <div>{ props.a }</div>;
|
||||
|
||||
// ok
|
||||
const a1 = <Foo {...props}></Foo>;
|
||||
const a2 = <Foo d={1} {...props}></Foo>;
|
||||
|
||||
// error
|
||||
const b1 = <Foo a={1} {...props}></Foo>;
|
||||
const b2 = <Foo a={1} b={2} {...props}></Foo>;
|
||||
const b3 = <Foo a={1} d={1} {...props} {...{ d: 1 }}></Foo>;
|
||||
const b4 = <Foo a={1} d={1} {...props} {...{ a: 1, d: 1 }}></Foo>;
|
||||
Reference in New Issue
Block a user