Perform excess property checking on intersection and union members (#30853)

* Perform excess property checking on intersection and union members

* Allow partial union props to contain the undefined type

* Add test case from #30771

* Un-terse getPossiblePropertiesOfUnionType side-effecting code

* Fix bug exposed in RWC

* Cache results of getPossiblePropertiesOfUnionType

* Fix whitespace
This commit is contained in:
Wesley Wigham 2019-04-16 21:58:48 -07:00 committed by GitHub
parent f617d1641b
commit 169e485d90
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 1414 additions and 62 deletions

View file

@ -7473,6 +7473,25 @@ namespace ts {
return type.resolvedProperties;
}
function getPossiblePropertiesOfUnionType(type: UnionType): Symbol[] {
if (type.possiblePropertyCache) {
return type.possiblePropertyCache.size ? arrayFrom(type.possiblePropertyCache.values()) : emptyArray;
}
type.possiblePropertyCache = createSymbolTable();
for (const t of type.types) {
for (const p of getPropertiesOfType(t)) {
if (!type.possiblePropertyCache.has(p.escapedName)) {
const prop = getUnionOrIntersectionProperty(type, p.escapedName);
if (prop) {
type.possiblePropertyCache.set(p.escapedName, prop);
}
}
}
}
// We can't simply use the normal property cache here, since that will contain cached apparent type members :(
return type.possiblePropertyCache.size ? arrayFrom(type.possiblePropertyCache.values()) : emptyArray;
}
function getPropertiesOfType(type: Type): Symbol[] {
type = getApparentType(type);
return type.flags & TypeFlags.UnionOrIntersection ?
@ -7830,7 +7849,7 @@ namespace ts {
const isUnion = containingType.flags & TypeFlags.Union;
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
// Flags we want to propagate to the result if they exist in all source symbols
let commonFlags = isUnion ? SymbolFlags.None : SymbolFlags.Optional;
let optionalFlag = isUnion ? SymbolFlags.None : SymbolFlags.Optional;
let syntheticFlag = CheckFlags.SyntheticMethod;
let checkFlags = 0;
for (const current of containingType.types) {
@ -7839,7 +7858,12 @@ namespace ts {
const prop = getPropertyOfType(type, name);
const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0;
if (prop && !(modifiers & excludeModifiers)) {
commonFlags &= prop.flags;
if (isUnion) {
optionalFlag |= (prop.flags & SymbolFlags.Optional);
}
else {
optionalFlag &= prop.flags;
}
const id = "" + getSymbolId(prop);
if (!propSet.has(id)) {
propSet.set(id, prop);
@ -7857,10 +7881,11 @@ namespace ts {
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;
indexTypes = append(indexTypes, isTupleType(type) ? getRestTypeOfTupleType(type) || undefinedType : indexInfo.type);
}
else {
checkFlags |= CheckFlags.Partial;
checkFlags |= CheckFlags.ReadPartial;
}
}
}
@ -7869,7 +7894,7 @@ namespace ts {
return undefined;
}
const props = arrayFrom(propSet.values());
if (props.length === 1 && !(checkFlags & CheckFlags.Partial) && !indexTypes) {
if (props.length === 1 && !(checkFlags & CheckFlags.ReadPartial) && !indexTypes) {
return props[0];
}
let declarations: Declaration[] | undefined;
@ -7900,7 +7925,7 @@ namespace ts {
propTypes.push(type);
}
addRange(propTypes, indexTypes);
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
const result = createSymbol(SymbolFlags.Property | optionalFlag, name, syntheticFlag | checkFlags);
result.containingType = containingType;
if (!hasNonUniformValueDeclaration && firstValueDeclaration) {
result.valueDeclaration = firstValueDeclaration;
@ -7937,7 +7962,7 @@ namespace ts {
function getPropertyOfUnionOrIntersectionType(type: UnionOrIntersectionType, name: __String): Symbol | undefined {
const property = getUnionOrIntersectionProperty(type, name);
// We need to filter out partial properties in union types
return property && !(getCheckFlags(property) & CheckFlags.Partial) ? property : undefined;
return property && !(getCheckFlags(property) & CheckFlags.ReadPartial) ? property : undefined;
}
/**
@ -12276,25 +12301,6 @@ namespace ts {
return true;
}
function isUnionOrIntersectionTypeWithoutNullableConstituents(type: Type): boolean {
if (!(type.flags & TypeFlags.UnionOrIntersection)) {
return false;
}
// at this point we know that this is union or intersection type possibly with nullable constituents.
// check if we still will have compound type if we ignore nullable components.
let seenNonNullable = false;
for (const t of (<UnionOrIntersectionType>type).types) {
if (t.flags & TypeFlags.Nullable) {
continue;
}
if (seenNonNullable) {
return true;
}
seenNonNullable = true;
}
return false;
}
/**
* Compare two types and return
* * Ternary.True if they are related with no assumptions,
@ -12349,7 +12355,8 @@ namespace ts {
isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
if (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral) {
const isPerformingExcessPropertyChecks = (isObjectLiteralType(source) && getObjectFlags(source) & ObjectFlags.FreshLiteral);
if (isPerformingExcessPropertyChecks) {
const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined;
if (hasExcessProperties(<FreshObjectLiteralType>source, target, discriminantType, reportErrors)) {
if (reportErrors) {
@ -12357,13 +12364,6 @@ namespace ts {
}
return Ternary.False;
}
// Above we check for excess properties with respect to the entire target type. When union
// and intersection types are further deconstructed on the target side, we don't want to
// make the check again (as it might fail for a partial target type). Therefore we obtain
// the regular source type and proceed with that.
if (isUnionOrIntersectionTypeWithoutNullableConstituents(target) && !discriminantType) {
source = getRegularTypeOfObjectLiteral(source);
}
}
if (relation !== comparableRelation && !isApparentIntersectionConstituent &&
@ -12399,11 +12399,24 @@ namespace ts {
}
else {
if (target.flags & TypeFlags.Union) {
result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
result = typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
if (result && isPerformingExcessPropertyChecks) {
// Validate against excess props using the original `source`
const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined;
if (!propertiesRelatedTo(source, discriminantType || target, reportErrors)) {
return Ternary.False;
}
}
}
else if (target.flags & TypeFlags.Intersection) {
isIntersectionConstituent = true; // set here to affect the following trio of checks
result = typeRelatedToEachType(source, target as IntersectionType, reportErrors);
result = typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors);
if (result && isPerformingExcessPropertyChecks) {
// Validate against excess props using the original `source`
if (!propertiesRelatedTo(source, target, reportErrors)) {
return Ternary.False;
}
}
}
else if (source.flags & TypeFlags.Intersection) {
// Check to see if any constituents of the intersection are immediately related to the target.
@ -12506,7 +12519,7 @@ namespace ts {
// check excess properties against discriminant type only, not the entire union
return hasExcessProperties(source, discriminant, /*discriminant*/ undefined, reportErrors);
}
for (const prop of getPropertiesOfObjectType(source)) {
for (const prop of getPropertiesOfType(source)) {
if (shouldCheckAsExcessProperty(prop, source.symbol) && !isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
if (reportErrors) {
// Report error in terms of object types in the target as those are the only ones
@ -13233,7 +13246,9 @@ namespace ts {
}
}
}
const properties = getPropertiesOfObjectType(target);
// We only call this for union target types when we're attempting to do excess property checking - in those cases, we want to get _all possible props_
// from the target union, across all members
const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target);
for (const targetProp of properties) {
if (!(targetProp.flags & SymbolFlags.Prototype)) {
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
@ -13281,7 +13296,8 @@ namespace ts {
}
return Ternary.False;
}
const related = isRelatedTo(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp), reportErrors);
// If the target comes from a partial union prop, allow `undefined` in the target type
const related = isRelatedTo(getTypeOfSymbol(sourceProp), addOptionality(getTypeOfSymbol(targetProp), !!(getCheckFlags(targetProp) & CheckFlags.Partial)), reportErrors);
if (!related) {
if (reportErrors) {
reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
@ -14627,9 +14643,9 @@ namespace ts {
}
function* getUnmatchedProperties(source: Type, target: Type, requireOptionalProperties: boolean, matchDiscriminantProperties: boolean) {
const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(<IntersectionType>target) : getPropertiesOfObjectType(target);
const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target);
for (const targetProp of properties) {
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) {
if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional || getCheckFlags(targetProp) & CheckFlags.Partial)) {
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
if (!sourceProp) {
yield targetProp;

View file

@ -3746,19 +3746,21 @@ namespace ts {
SyntheticProperty = 1 << 1, // Property in union or intersection type
SyntheticMethod = 1 << 2, // Method in union or intersection type
Readonly = 1 << 3, // Readonly transient symbol
Partial = 1 << 4, // Synthetic property present in some but not all constituents
HasNonUniformType = 1 << 5, // Synthetic property with non-uniform type in constituents
HasLiteralType = 1 << 6, // Synthetic property with at least one literal type in constituents
ContainsPublic = 1 << 7, // Synthetic property with public constituent(s)
ContainsProtected = 1 << 8, // Synthetic property with protected constituent(s)
ContainsPrivate = 1 << 9, // Synthetic property with private constituent(s)
ContainsStatic = 1 << 10, // Synthetic property with static constituent(s)
Late = 1 << 11, // Late-bound symbol for a computed property with a dynamic name
ReverseMapped = 1 << 12, // Property of reverse-inferred homomorphic mapped type
OptionalParameter = 1 << 13, // Optional parameter
RestParameter = 1 << 14, // Rest parameter
ReadPartial = 1 << 4, // Synthetic property present in some but not all constituents
WritePartial = 1 << 5, // Synthetic property present in some but only satisfied by an index signature in others
HasNonUniformType = 1 << 6, // Synthetic property with non-uniform type in constituents
HasLiteralType = 1 << 7, // Synthetic property with at least one literal type in constituents
ContainsPublic = 1 << 8, // Synthetic property with public constituent(s)
ContainsProtected = 1 << 9, // Synthetic property with protected constituent(s)
ContainsPrivate = 1 << 10, // Synthetic property with private constituent(s)
ContainsStatic = 1 << 11, // Synthetic property with static constituent(s)
Late = 1 << 12, // Late-bound symbol for a computed property with a dynamic name
ReverseMapped = 1 << 13, // Property of reverse-inferred homomorphic mapped type
OptionalParameter = 1 << 14, // Optional parameter
RestParameter = 1 << 15, // Rest parameter
Synthetic = SyntheticProperty | SyntheticMethod,
Discriminant = HasNonUniformType | HasLiteralType
Discriminant = HasNonUniformType | HasLiteralType,
Partial = ReadPartial | WritePartial
}
/* @internal */
@ -4171,6 +4173,8 @@ namespace ts {
}
export interface UnionType extends UnionOrIntersectionType {
/* @internal */
possiblePropertyCache?: SymbolTable; // Cache of _all_ resolved properties less any from aparent members
}
export interface IntersectionType extends UnionOrIntersectionType {

View file

@ -0,0 +1,48 @@
tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts(21,33): error TS2322: Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'.
Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'.
tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts(27,34): error TS2326: Types of property 'icon' are incompatible.
Type '{ props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }' is not assignable to type 'NestedProp<ITestProps>'.
Types of property 'props' are incompatible.
Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'.
Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'.
==== tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts (2 errors) ====
interface StatelessComponent<P = {}> {
(props: P & { children?: number }, context?: any): null;
}
const TestComponent: StatelessComponent<TestProps> = (props) => {
return null;
}
interface ITestProps {
ariaLabel?: string;
}
interface NestedProp<TProps> {
props: TProps;
}
interface TestProps {
icon: NestedProp<ITestProps>;
}
TestComponent({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'.
!!! error TS2322: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'.
!!! related TS6500 tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts:14:3: The expected type comes from property 'props' which is declared here on type 'NestedProp<ITestProps>'
const TestComponent2: StatelessComponent<TestProps | {props2: {x: number}}> = (props) => {
return null;
}
TestComponent2({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2326: Types of property 'icon' are incompatible.
!!! error TS2326: Type '{ props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }' is not assignable to type 'NestedProp<ITestProps>'.
!!! error TS2326: Types of property 'props' are incompatible.
!!! error TS2326: Type '{ INVALID_PROP_NAME: string; ariaLabel: string; }' is not assignable to type 'ITestProps'.
!!! error TS2326: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'ITestProps'.

View file

@ -0,0 +1,39 @@
//// [deepExcessPropertyCheckingWhenTargetIsIntersection.ts]
interface StatelessComponent<P = {}> {
(props: P & { children?: number }, context?: any): null;
}
const TestComponent: StatelessComponent<TestProps> = (props) => {
return null;
}
interface ITestProps {
ariaLabel?: string;
}
interface NestedProp<TProps> {
props: TProps;
}
interface TestProps {
icon: NestedProp<ITestProps>;
}
TestComponent({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
const TestComponent2: StatelessComponent<TestProps | {props2: {x: number}}> = (props) => {
return null;
}
TestComponent2({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
//// [deepExcessPropertyCheckingWhenTargetIsIntersection.js]
var TestComponent = function (props) {
return null;
};
TestComponent({ icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } } });
var TestComponent2 = function (props) {
return null;
};
TestComponent2({ icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } } });

View file

@ -0,0 +1,71 @@
=== tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts ===
interface StatelessComponent<P = {}> {
>StatelessComponent : Symbol(StatelessComponent, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 0, 0))
>P : Symbol(P, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 0, 29))
(props: P & { children?: number }, context?: any): null;
>props : Symbol(props, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 1, 3))
>P : Symbol(P, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 0, 29))
>children : Symbol(children, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 1, 15))
>context : Symbol(context, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 1, 36))
}
const TestComponent: StatelessComponent<TestProps> = (props) => {
>TestComponent : Symbol(TestComponent, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 4, 5))
>StatelessComponent : Symbol(StatelessComponent, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 0, 0))
>TestProps : Symbol(TestProps, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 14, 1))
>props : Symbol(props, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 4, 54))
return null;
}
interface ITestProps {
>ITestProps : Symbol(ITestProps, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 6, 1))
ariaLabel?: string;
>ariaLabel : Symbol(ITestProps.ariaLabel, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 8, 22))
}
interface NestedProp<TProps> {
>NestedProp : Symbol(NestedProp, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 10, 1))
>TProps : Symbol(TProps, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 12, 21))
props: TProps;
>props : Symbol(NestedProp.props, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 12, 30))
>TProps : Symbol(TProps, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 12, 21))
}
interface TestProps {
>TestProps : Symbol(TestProps, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 14, 1))
icon: NestedProp<ITestProps>;
>icon : Symbol(TestProps.icon, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 16, 21))
>NestedProp : Symbol(NestedProp, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 10, 1))
>ITestProps : Symbol(ITestProps, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 6, 1))
}
TestComponent({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
>TestComponent : Symbol(TestComponent, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 4, 5))
>icon : Symbol(icon, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 20, 15))
>props : Symbol(props, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 20, 22))
>INVALID_PROP_NAME : Symbol(INVALID_PROP_NAME, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 20, 31))
>ariaLabel : Symbol(ariaLabel, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 20, 59))
const TestComponent2: StatelessComponent<TestProps | {props2: {x: number}}> = (props) => {
>TestComponent2 : Symbol(TestComponent2, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 22, 5))
>StatelessComponent : Symbol(StatelessComponent, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 0, 0))
>TestProps : Symbol(TestProps, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 14, 1))
>props2 : Symbol(props2, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 22, 54))
>x : Symbol(x, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 22, 63))
>props : Symbol(props, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 22, 79))
return null;
}
TestComponent2({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
>TestComponent2 : Symbol(TestComponent2, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 22, 5))
>icon : Symbol(icon, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 26, 16))
>props : Symbol(props, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 26, 23))
>INVALID_PROP_NAME : Symbol(INVALID_PROP_NAME, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 26, 32))
>ariaLabel : Symbol(ariaLabel, Decl(deepExcessPropertyCheckingWhenTargetIsIntersection.ts, 26, 60))

View file

@ -0,0 +1,70 @@
=== tests/cases/compiler/deepExcessPropertyCheckingWhenTargetIsIntersection.ts ===
interface StatelessComponent<P = {}> {
(props: P & { children?: number }, context?: any): null;
>props : P & { children?: number; }
>children : number
>context : any
>null : null
}
const TestComponent: StatelessComponent<TestProps> = (props) => {
>TestComponent : StatelessComponent<TestProps>
>(props) => { return null;} : (props: TestProps & { children?: number; }) => any
>props : TestProps & { children?: number; }
return null;
>null : null
}
interface ITestProps {
ariaLabel?: string;
>ariaLabel : string
}
interface NestedProp<TProps> {
props: TProps;
>props : TProps
}
interface TestProps {
icon: NestedProp<ITestProps>;
>icon : NestedProp<ITestProps>
}
TestComponent({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
>TestComponent({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }}) : null
>TestComponent : StatelessComponent<TestProps>
>{icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }} : { icon: { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }; }
>icon : { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }
>{ props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } } : { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }
>props : { INVALID_PROP_NAME: string; ariaLabel: string; }
>{ INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } : { INVALID_PROP_NAME: string; ariaLabel: string; }
>INVALID_PROP_NAME : string
>'share' : "share"
>ariaLabel : string
>'test label' : "test label"
const TestComponent2: StatelessComponent<TestProps | {props2: {x: number}}> = (props) => {
>TestComponent2 : StatelessComponent<TestProps | { props2: { x: number; }; }>
>props2 : { x: number; }
>x : number
>(props) => { return null;} : (props: (TestProps & { children?: number; }) | ({ props2: { x: number; }; } & { children?: number; })) => any
>props : (TestProps & { children?: number; }) | ({ props2: { x: number; }; } & { children?: number; })
return null;
>null : null
}
TestComponent2({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
>TestComponent2({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }}) : null
>TestComponent2 : StatelessComponent<TestProps | { props2: { x: number; }; }>
>{icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }} : { icon: { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }; }
>icon : { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }
>{ props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } } : { props: { INVALID_PROP_NAME: string; ariaLabel: string; }; }
>props : { INVALID_PROP_NAME: string; ariaLabel: string; }
>{ INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } : { INVALID_PROP_NAME: string; ariaLabel: string; }
>INVALID_PROP_NAME : string
>'share' : "share"
>ariaLabel : string
>'test label' : "test label"

View file

@ -20,11 +20,9 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(49,35): error TS2322: Type
Object literal may only specify known properties, and 'second' does not exist in type '{ a: 1; b: 1; first: string; }'.
tests/cases/compiler/excessPropertyCheckWithUnions.ts(50,35): error TS2322: Type '{ a: 1; b: 1; first: string; third: string; }' is not assignable to type 'Overlapping'.
Object literal may only specify known properties, and 'third' does not exist in type '{ a: 1; b: 1; first: string; }'.
tests/cases/compiler/excessPropertyCheckWithUnions.ts(66,9): error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'.
Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type '{ kind: "A"; n: AN; }'.
Types of property 'n' are incompatible.
Type '{ a: string; b: string; }' is not assignable to type 'AN'.
Object literal may only specify known properties, and 'b' does not exist in type 'AN'.
tests/cases/compiler/excessPropertyCheckWithUnions.ts(66,9): error TS2326: Types of property 'n' are incompatible.
Type '{ a: string; b: string; }' is not assignable to type 'AN'.
Object literal may only specify known properties, and 'b' does not exist in type 'AN'.
==== tests/cases/compiler/excessPropertyCheckWithUnions.ts (10 errors) ====
@ -127,11 +125,9 @@ tests/cases/compiler/excessPropertyCheckWithUnions.ts(66,9): error TS2322: Type
a: "a",
b: "b", // excess -- kind: "A"
~~~~~~
!!! error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type 'AB'.
!!! error TS2322: Type '{ kind: "A"; n: { a: string; b: string; }; }' is not assignable to type '{ kind: "A"; n: AN; }'.
!!! error TS2322: Types of property 'n' are incompatible.
!!! error TS2322: Type '{ a: string; b: string; }' is not assignable to type 'AN'.
!!! error TS2322: Object literal may only specify known properties, and 'b' does not exist in type 'AN'.
!!! error TS2326: Types of property 'n' are incompatible.
!!! error TS2326: Type '{ a: string; b: string; }' is not assignable to type 'AN'.
!!! error TS2326: Object literal may only specify known properties, and 'b' does not exist in type 'AN'.
}
}
const abac: AB = {

View file

@ -0,0 +1,116 @@
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(18,19): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(19,31): error TS2322: Type '{ x: string; y: number; }' is not assignable to type 'A'.
Object literal may only specify known properties, and 'y' does not exist in type 'A'.
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(22,19): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(23,31): error TS2322: Type '{ x: string; y: number; }' is not assignable to type 'A'.
Object literal may only specify known properties, and 'y' does not exist in type 'A'.
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(34,5): error TS2322: Type '{ id: number; url: string; xyz: number; }' is not assignable to type '{ id: number; } & { url: string; }'.
Object literal may only specify known properties, and 'xyz' does not exist in type '{ id: number; } & { url: string; }'.
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(43,9): error TS2322: Type '{ id: number; url: string; xyz: number; }' is not assignable to type '{ id: number; } & { url: string; }'.
Object literal may only specify known properties, and 'xyz' does not exist in type '{ id: number; } & { url: string; }'.
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(68,32): error TS2322: Type '{ foo: true; bar: true; boo: boolean; }' is not assignable to type 'View<TypeA>'.
Object literal may only specify known properties, and 'boo' does not exist in type 'View<TypeA>'.
tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts(70,50): error TS2322: Type '{ foo: true; bar: true; boo: boolean; }' is not assignable to type 'boolean | View<TypeB>'.
Object literal may only specify known properties, and 'boo' does not exist in type 'View<TypeB>'.
==== tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts (8 errors) ====
// https://github.com/Microsoft/TypeScript/issues/13813
interface A {
x: string
}
interface B {
a: A;
}
interface C {
c: number;
}
type D = B & C;
let a: B = { a: { x: 'hello' } }; // ok
let b: B = { a: { x: 2 } }; // error - types of property x are incompatible
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6500 tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts:4:5: The expected type comes from property 'x' which is declared here on type 'A'
let c: B = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
~~~~
!!! error TS2322: Type '{ x: string; y: number; }' is not assignable to type 'A'.
!!! error TS2322: Object literal may only specify known properties, and 'y' does not exist in type 'A'.
!!! related TS6500 tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts:8:5: The expected type comes from property 'a' which is declared here on type 'B'
let d: D = { a: { x: 'hello' }, c: 5 }; // ok
let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6500 tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts:4:5: The expected type comes from property 'x' which is declared here on type 'A'
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
~~~~
!!! error TS2322: Type '{ x: string; y: number; }' is not assignable to type 'A'.
!!! error TS2322: Object literal may only specify known properties, and 'y' does not exist in type 'A'.
!!! related TS6500 tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts:8:5: The expected type comes from property 'a' which is declared here on type 'D'
// https://github.com/Microsoft/TypeScript/issues/18075
export type MyType = { id: number; } & { name: string; } & { photo: { id: number; } & { url: string; } }
export let obj: MyType;
export const photo: typeof obj.photo = {
id: 1,
url: '',
xyz: 1 // Great! This causes an error!
~~~~~~
!!! error TS2322: Type '{ id: number; url: string; xyz: number; }' is not assignable to type '{ id: number; } & { url: string; }'.
!!! error TS2322: Object literal may only specify known properties, and 'xyz' does not exist in type '{ id: number; } & { url: string; }'.
};
export const myInstance: MyType = {
id: 1,
name: '',
photo: {
id: 1,
url: '',
xyz: 2 // This should also be an error
~~~~~~
!!! error TS2322: Type '{ id: number; url: string; xyz: number; }' is not assignable to type '{ id: number; } & { url: string; }'.
!!! error TS2322: Object literal may only specify known properties, and 'xyz' does not exist in type '{ id: number; } & { url: string; }'.
!!! related TS6500 tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts:27:62: The expected type comes from property 'photo' which is declared here on type 'MyType'
}
};
// https://github.com/Microsoft/TypeScript/issues/28616
export type View<T> = { [K in keyof T]: T[K] extends object ? boolean | View<T[K]> : boolean };
interface TypeC {
foo: string;
bar: string;
}
interface TypeB {
foo: string,
bar: TypeC
}
interface TypeA {
foo: string,
bar: TypeB,
}
let test: View<TypeA>;
test = { foo: true, bar: true, boo: true }
~~~~~~~~~
!!! error TS2322: Type '{ foo: true; bar: true; boo: boolean; }' is not assignable to type 'View<TypeA>'.
!!! error TS2322: Object literal may only specify known properties, and 'boo' does not exist in type 'View<TypeA>'.
test = { foo: true, bar: { foo: true, bar: true, boo: true } }
~~~~~~~~~
!!! error TS2322: Type '{ foo: true; bar: true; boo: boolean; }' is not assignable to type 'boolean | View<TypeB>'.
!!! error TS2322: Object literal may only specify known properties, and 'boo' does not exist in type 'View<TypeB>'.
!!! related TS6500 tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts:63:5: The expected type comes from property 'bar' which is declared here on type 'View<TypeA>'

View file

@ -0,0 +1,100 @@
//// [excessPropertyChecksWithNestedIntersections.ts]
// https://github.com/Microsoft/TypeScript/issues/13813
interface A {
x: string
}
interface B {
a: A;
}
interface C {
c: number;
}
type D = B & C;
let a: B = { a: { x: 'hello' } }; // ok
let b: B = { a: { x: 2 } }; // error - types of property x are incompatible
let c: B = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
let d: D = { a: { x: 'hello' }, c: 5 }; // ok
let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
// https://github.com/Microsoft/TypeScript/issues/18075
export type MyType = { id: number; } & { name: string; } & { photo: { id: number; } & { url: string; } }
export let obj: MyType;
export const photo: typeof obj.photo = {
id: 1,
url: '',
xyz: 1 // Great! This causes an error!
};
export const myInstance: MyType = {
id: 1,
name: '',
photo: {
id: 1,
url: '',
xyz: 2 // This should also be an error
}
};
// https://github.com/Microsoft/TypeScript/issues/28616
export type View<T> = { [K in keyof T]: T[K] extends object ? boolean | View<T[K]> : boolean };
interface TypeC {
foo: string;
bar: string;
}
interface TypeB {
foo: string,
bar: TypeC
}
interface TypeA {
foo: string,
bar: TypeB,
}
let test: View<TypeA>;
test = { foo: true, bar: true, boo: true }
test = { foo: true, bar: { foo: true, bar: true, boo: true } }
//// [excessPropertyChecksWithNestedIntersections.js]
"use strict";
// https://github.com/Microsoft/TypeScript/issues/13813
exports.__esModule = true;
var a = { a: { x: 'hello' } }; // ok
var b = { a: { x: 2 } }; // error - types of property x are incompatible
var c = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
var d = { a: { x: 'hello' }, c: 5 }; // ok
var e = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
var f = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
exports.photo = {
id: 1,
url: '',
xyz: 1 // Great! This causes an error!
};
exports.myInstance = {
id: 1,
name: '',
photo: {
id: 1,
url: '',
xyz: 2 // This should also be an error
}
};
var test;
test = { foo: true, bar: true, boo: true };
test = { foo: true, bar: { foo: true, bar: true, boo: true } };

View file

@ -0,0 +1,190 @@
=== tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts ===
// https://github.com/Microsoft/TypeScript/issues/13813
interface A {
>A : Symbol(A, Decl(excessPropertyChecksWithNestedIntersections.ts, 0, 0))
x: string
>x : Symbol(A.x, Decl(excessPropertyChecksWithNestedIntersections.ts, 2, 13))
}
interface B {
>B : Symbol(B, Decl(excessPropertyChecksWithNestedIntersections.ts, 4, 1))
a: A;
>a : Symbol(B.a, Decl(excessPropertyChecksWithNestedIntersections.ts, 6, 13))
>A : Symbol(A, Decl(excessPropertyChecksWithNestedIntersections.ts, 0, 0))
}
interface C {
>C : Symbol(C, Decl(excessPropertyChecksWithNestedIntersections.ts, 8, 1))
c: number;
>c : Symbol(C.c, Decl(excessPropertyChecksWithNestedIntersections.ts, 10, 13))
}
type D = B & C;
>D : Symbol(D, Decl(excessPropertyChecksWithNestedIntersections.ts, 12, 1))
>B : Symbol(B, Decl(excessPropertyChecksWithNestedIntersections.ts, 4, 1))
>C : Symbol(C, Decl(excessPropertyChecksWithNestedIntersections.ts, 8, 1))
let a: B = { a: { x: 'hello' } }; // ok
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 16, 3))
>B : Symbol(B, Decl(excessPropertyChecksWithNestedIntersections.ts, 4, 1))
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 16, 12))
>x : Symbol(x, Decl(excessPropertyChecksWithNestedIntersections.ts, 16, 17))
let b: B = { a: { x: 2 } }; // error - types of property x are incompatible
>b : Symbol(b, Decl(excessPropertyChecksWithNestedIntersections.ts, 17, 3))
>B : Symbol(B, Decl(excessPropertyChecksWithNestedIntersections.ts, 4, 1))
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 17, 12))
>x : Symbol(x, Decl(excessPropertyChecksWithNestedIntersections.ts, 17, 17))
let c: B = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
>c : Symbol(c, Decl(excessPropertyChecksWithNestedIntersections.ts, 18, 3))
>B : Symbol(B, Decl(excessPropertyChecksWithNestedIntersections.ts, 4, 1))
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 18, 12))
>x : Symbol(x, Decl(excessPropertyChecksWithNestedIntersections.ts, 18, 17))
>y : Symbol(y, Decl(excessPropertyChecksWithNestedIntersections.ts, 18, 29))
let d: D = { a: { x: 'hello' }, c: 5 }; // ok
>d : Symbol(d, Decl(excessPropertyChecksWithNestedIntersections.ts, 20, 3))
>D : Symbol(D, Decl(excessPropertyChecksWithNestedIntersections.ts, 12, 1))
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 20, 12))
>x : Symbol(x, Decl(excessPropertyChecksWithNestedIntersections.ts, 20, 17))
>c : Symbol(c, Decl(excessPropertyChecksWithNestedIntersections.ts, 20, 31))
let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
>e : Symbol(e, Decl(excessPropertyChecksWithNestedIntersections.ts, 21, 3))
>D : Symbol(D, Decl(excessPropertyChecksWithNestedIntersections.ts, 12, 1))
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 21, 12))
>x : Symbol(x, Decl(excessPropertyChecksWithNestedIntersections.ts, 21, 17))
>c : Symbol(c, Decl(excessPropertyChecksWithNestedIntersections.ts, 21, 25))
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
>f : Symbol(f, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 3))
>D : Symbol(D, Decl(excessPropertyChecksWithNestedIntersections.ts, 12, 1))
>a : Symbol(a, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 12))
>x : Symbol(x, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 17))
>y : Symbol(y, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 29))
>c : Symbol(c, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 37))
// https://github.com/Microsoft/TypeScript/issues/18075
export type MyType = { id: number; } & { name: string; } & { photo: { id: number; } & { url: string; } }
>MyType : Symbol(MyType, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 45))
>id : Symbol(id, Decl(excessPropertyChecksWithNestedIntersections.ts, 26, 22))
>name : Symbol(name, Decl(excessPropertyChecksWithNestedIntersections.ts, 26, 40))
>photo : Symbol(photo, Decl(excessPropertyChecksWithNestedIntersections.ts, 26, 60))
>id : Symbol(id, Decl(excessPropertyChecksWithNestedIntersections.ts, 26, 69))
>url : Symbol(url, Decl(excessPropertyChecksWithNestedIntersections.ts, 26, 87))
export let obj: MyType;
>obj : Symbol(obj, Decl(excessPropertyChecksWithNestedIntersections.ts, 28, 10))
>MyType : Symbol(MyType, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 45))
export const photo: typeof obj.photo = {
>photo : Symbol(photo, Decl(excessPropertyChecksWithNestedIntersections.ts, 30, 12))
>obj.photo : Symbol(photo, Decl(excessPropertyChecksWithNestedIntersections.ts, 26, 60))
>obj : Symbol(obj, Decl(excessPropertyChecksWithNestedIntersections.ts, 28, 10))
>photo : Symbol(photo, Decl(excessPropertyChecksWithNestedIntersections.ts, 26, 60))
id: 1,
>id : Symbol(id, Decl(excessPropertyChecksWithNestedIntersections.ts, 30, 40))
url: '',
>url : Symbol(url, Decl(excessPropertyChecksWithNestedIntersections.ts, 31, 10))
xyz: 1 // Great! This causes an error!
>xyz : Symbol(xyz, Decl(excessPropertyChecksWithNestedIntersections.ts, 32, 12))
};
export const myInstance: MyType = {
>myInstance : Symbol(myInstance, Decl(excessPropertyChecksWithNestedIntersections.ts, 36, 12))
>MyType : Symbol(MyType, Decl(excessPropertyChecksWithNestedIntersections.ts, 22, 45))
id: 1,
>id : Symbol(id, Decl(excessPropertyChecksWithNestedIntersections.ts, 36, 35))
name: '',
>name : Symbol(name, Decl(excessPropertyChecksWithNestedIntersections.ts, 37, 10))
photo: {
>photo : Symbol(photo, Decl(excessPropertyChecksWithNestedIntersections.ts, 38, 13))
id: 1,
>id : Symbol(id, Decl(excessPropertyChecksWithNestedIntersections.ts, 39, 12))
url: '',
>url : Symbol(url, Decl(excessPropertyChecksWithNestedIntersections.ts, 40, 14))
xyz: 2 // This should also be an error
>xyz : Symbol(xyz, Decl(excessPropertyChecksWithNestedIntersections.ts, 41, 16))
}
};
// https://github.com/Microsoft/TypeScript/issues/28616
export type View<T> = { [K in keyof T]: T[K] extends object ? boolean | View<T[K]> : boolean };
>View : Symbol(View, Decl(excessPropertyChecksWithNestedIntersections.ts, 44, 2))
>T : Symbol(T, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 17))
>K : Symbol(K, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 25))
>T : Symbol(T, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 17))
>T : Symbol(T, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 17))
>K : Symbol(K, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 25))
>View : Symbol(View, Decl(excessPropertyChecksWithNestedIntersections.ts, 44, 2))
>T : Symbol(T, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 17))
>K : Symbol(K, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 25))
interface TypeC {
>TypeC : Symbol(TypeC, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 95))
foo: string;
>foo : Symbol(TypeC.foo, Decl(excessPropertyChecksWithNestedIntersections.ts, 50, 17))
bar: string;
>bar : Symbol(TypeC.bar, Decl(excessPropertyChecksWithNestedIntersections.ts, 51, 16))
}
interface TypeB {
>TypeB : Symbol(TypeB, Decl(excessPropertyChecksWithNestedIntersections.ts, 53, 1))
foo: string,
>foo : Symbol(TypeB.foo, Decl(excessPropertyChecksWithNestedIntersections.ts, 55, 17))
bar: TypeC
>bar : Symbol(TypeB.bar, Decl(excessPropertyChecksWithNestedIntersections.ts, 56, 16))
>TypeC : Symbol(TypeC, Decl(excessPropertyChecksWithNestedIntersections.ts, 48, 95))
}
interface TypeA {
>TypeA : Symbol(TypeA, Decl(excessPropertyChecksWithNestedIntersections.ts, 58, 1))
foo: string,
>foo : Symbol(TypeA.foo, Decl(excessPropertyChecksWithNestedIntersections.ts, 60, 17))
bar: TypeB,
>bar : Symbol(TypeA.bar, Decl(excessPropertyChecksWithNestedIntersections.ts, 61, 16))
>TypeB : Symbol(TypeB, Decl(excessPropertyChecksWithNestedIntersections.ts, 53, 1))
}
let test: View<TypeA>;
>test : Symbol(test, Decl(excessPropertyChecksWithNestedIntersections.ts, 65, 3))
>View : Symbol(View, Decl(excessPropertyChecksWithNestedIntersections.ts, 44, 2))
>TypeA : Symbol(TypeA, Decl(excessPropertyChecksWithNestedIntersections.ts, 58, 1))
test = { foo: true, bar: true, boo: true }
>test : Symbol(test, Decl(excessPropertyChecksWithNestedIntersections.ts, 65, 3))
>foo : Symbol(foo, Decl(excessPropertyChecksWithNestedIntersections.ts, 67, 8))
>bar : Symbol(bar, Decl(excessPropertyChecksWithNestedIntersections.ts, 67, 19))
>boo : Symbol(boo, Decl(excessPropertyChecksWithNestedIntersections.ts, 67, 30))
test = { foo: true, bar: { foo: true, bar: true, boo: true } }
>test : Symbol(test, Decl(excessPropertyChecksWithNestedIntersections.ts, 65, 3))
>foo : Symbol(foo, Decl(excessPropertyChecksWithNestedIntersections.ts, 69, 8))
>bar : Symbol(bar, Decl(excessPropertyChecksWithNestedIntersections.ts, 69, 19))
>foo : Symbol(foo, Decl(excessPropertyChecksWithNestedIntersections.ts, 69, 26))
>bar : Symbol(bar, Decl(excessPropertyChecksWithNestedIntersections.ts, 69, 37))
>boo : Symbol(boo, Decl(excessPropertyChecksWithNestedIntersections.ts, 69, 48))

View file

@ -0,0 +1,201 @@
=== tests/cases/compiler/excessPropertyChecksWithNestedIntersections.ts ===
// https://github.com/Microsoft/TypeScript/issues/13813
interface A {
x: string
>x : string
}
interface B {
a: A;
>a : A
}
interface C {
c: number;
>c : number
}
type D = B & C;
>D : D
let a: B = { a: { x: 'hello' } }; // ok
>a : B
>{ a: { x: 'hello' } } : { a: { x: string; }; }
>a : { x: string; }
>{ x: 'hello' } : { x: string; }
>x : string
>'hello' : "hello"
let b: B = { a: { x: 2 } }; // error - types of property x are incompatible
>b : B
>{ a: { x: 2 } } : { a: { x: number; }; }
>a : { x: number; }
>{ x: 2 } : { x: number; }
>x : number
>2 : 2
let c: B = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
>c : B
>{ a: { x: 'hello', y: 2 } } : { a: { x: string; y: number; }; }
>a : { x: string; y: number; }
>{ x: 'hello', y: 2 } : { x: string; y: number; }
>x : string
>'hello' : "hello"
>y : number
>2 : 2
let d: D = { a: { x: 'hello' }, c: 5 }; // ok
>d : D
>{ a: { x: 'hello' }, c: 5 } : { a: { x: string; }; c: number; }
>a : { x: string; }
>{ x: 'hello' } : { x: string; }
>x : string
>'hello' : "hello"
>c : number
>5 : 5
let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
>e : D
>{ a: { x: 2 }, c: 5 } : { a: { x: number; }; c: number; }
>a : { x: number; }
>{ x: 2 } : { x: number; }
>x : number
>2 : 2
>c : number
>5 : 5
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
>f : D
>{ a: { x: 'hello', y: 2 }, c: 5 } : { a: { x: string; y: number; }; c: number; }
>a : { x: string; y: number; }
>{ x: 'hello', y: 2 } : { x: string; y: number; }
>x : string
>'hello' : "hello"
>y : number
>2 : 2
>c : number
>5 : 5
// https://github.com/Microsoft/TypeScript/issues/18075
export type MyType = { id: number; } & { name: string; } & { photo: { id: number; } & { url: string; } }
>MyType : MyType
>id : number
>name : string
>photo : { id: number; } & { url: string; }
>id : number
>url : string
export let obj: MyType;
>obj : MyType
export const photo: typeof obj.photo = {
>photo : { id: number; } & { url: string; }
>obj.photo : { id: number; } & { url: string; }
>obj : MyType
>photo : { id: number; } & { url: string; }
>{ id: 1, url: '', xyz: 1 // Great! This causes an error!} : { id: number; url: string; xyz: number; }
id: 1,
>id : number
>1 : 1
url: '',
>url : string
>'' : ""
xyz: 1 // Great! This causes an error!
>xyz : number
>1 : 1
};
export const myInstance: MyType = {
>myInstance : MyType
>{ id: 1, name: '', photo: { id: 1, url: '', xyz: 2 // This should also be an error }} : { id: number; name: string; photo: { id: number; url: string; xyz: number; }; }
id: 1,
>id : number
>1 : 1
name: '',
>name : string
>'' : ""
photo: {
>photo : { id: number; url: string; xyz: number; }
>{ id: 1, url: '', xyz: 2 // This should also be an error } : { id: number; url: string; xyz: number; }
id: 1,
>id : number
>1 : 1
url: '',
>url : string
>'' : ""
xyz: 2 // This should also be an error
>xyz : number
>2 : 2
}
};
// https://github.com/Microsoft/TypeScript/issues/28616
export type View<T> = { [K in keyof T]: T[K] extends object ? boolean | View<T[K]> : boolean };
>View : View<T>
interface TypeC {
foo: string;
>foo : string
bar: string;
>bar : string
}
interface TypeB {
foo: string,
>foo : string
bar: TypeC
>bar : TypeC
}
interface TypeA {
foo: string,
>foo : string
bar: TypeB,
>bar : TypeB
}
let test: View<TypeA>;
>test : View<TypeA>
test = { foo: true, bar: true, boo: true }
>test = { foo: true, bar: true, boo: true } : { foo: true; bar: true; boo: boolean; }
>test : View<TypeA>
>{ foo: true, bar: true, boo: true } : { foo: true; bar: true; boo: boolean; }
>foo : true
>true : true
>bar : true
>true : true
>boo : boolean
>true : true
test = { foo: true, bar: { foo: true, bar: true, boo: true } }
>test = { foo: true, bar: { foo: true, bar: true, boo: true } } : { foo: true; bar: { foo: true; bar: true; boo: boolean; }; }
>test : View<TypeA>
>{ foo: true, bar: { foo: true, bar: true, boo: true } } : { foo: true; bar: { foo: true; bar: true; boo: boolean; }; }
>foo : true
>true : true
>bar : { foo: true; bar: true; boo: boolean; }
>{ foo: true, bar: true, boo: true } : { foo: true; bar: true; boo: boolean; }
>foo : true
>true : true
>bar : true
>true : true
>boo : boolean
>true : true

View file

@ -0,0 +1,44 @@
tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(13,35): error TS2322: Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'number | IProps'.
Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'.
tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(16,7): error TS2322: Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'number | IProps'.
Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'IProps'.
Types of property 'nestedProp' are incompatible.
Type '{ asdfasdf: string; }' has no properties in common with type '{ testBool?: boolean; }'.
tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts(19,56): error TS2326: Types of property 'nestedProps' are incompatible.
Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'IProps'.
Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'.
==== tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts (3 errors) ====
interface IProps {
iconProp?: string;
nestedProp?: {
testBool?: boolean;
}
}
interface INestedProps {
nestedProps?: IProps;
}
// These are the types of errors we want:
const propB1: IProps | number = { INVALID_PROP_NAME: 'share', iconProp: 'test' };
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'number | IProps'.
!!! error TS2322: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'.
// Nested typing works here and we also get an expected error:
const propB2: IProps | number = { nestedProp: { asdfasdf: 'test' }, iconProp: 'test' };
~~~~~~
!!! error TS2322: Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'number | IProps'.
!!! error TS2322: Type '{ nestedProp: { asdfasdf: string; }; iconProp: string; }' is not assignable to type 'IProps'.
!!! error TS2322: Types of property 'nestedProp' are incompatible.
!!! error TS2322: Type '{ asdfasdf: string; }' has no properties in common with type '{ testBool?: boolean; }'.
// Want an error generated here but there isn't one.
const propA1: INestedProps | number = { nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } };
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2326: Types of property 'nestedProps' are incompatible.
!!! error TS2326: Type '{ INVALID_PROP_NAME: string; iconProp: string; }' is not assignable to type 'IProps'.
!!! error TS2326: Object literal may only specify known properties, and 'INVALID_PROP_NAME' does not exist in type 'IProps'.

View file

@ -0,0 +1,29 @@
//// [nonObjectUnionNestedExcessPropertyCheck.ts]
interface IProps {
iconProp?: string;
nestedProp?: {
testBool?: boolean;
}
}
interface INestedProps {
nestedProps?: IProps;
}
// These are the types of errors we want:
const propB1: IProps | number = { INVALID_PROP_NAME: 'share', iconProp: 'test' };
// Nested typing works here and we also get an expected error:
const propB2: IProps | number = { nestedProp: { asdfasdf: 'test' }, iconProp: 'test' };
// Want an error generated here but there isn't one.
const propA1: INestedProps | number = { nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } };
//// [nonObjectUnionNestedExcessPropertyCheck.js]
// These are the types of errors we want:
var propB1 = { INVALID_PROP_NAME: 'share', iconProp: 'test' };
// Nested typing works here and we also get an expected error:
var propB2 = { nestedProp: { asdfasdf: 'test' }, iconProp: 'test' };
// Want an error generated here but there isn't one.
var propA1 = { nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } };

View file

@ -0,0 +1,46 @@
=== tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts ===
interface IProps {
>IProps : Symbol(IProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 0, 0))
iconProp?: string;
>iconProp : Symbol(IProps.iconProp, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 0, 18))
nestedProp?: {
>nestedProp : Symbol(IProps.nestedProp, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 1, 22))
testBool?: boolean;
>testBool : Symbol(testBool, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 2, 18))
}
}
interface INestedProps {
>INestedProps : Symbol(INestedProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 5, 1))
nestedProps?: IProps;
>nestedProps : Symbol(INestedProps.nestedProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 7, 24))
>IProps : Symbol(IProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 0, 0))
}
// These are the types of errors we want:
const propB1: IProps | number = { INVALID_PROP_NAME: 'share', iconProp: 'test' };
>propB1 : Symbol(propB1, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 12, 5))
>IProps : Symbol(IProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 0, 0))
>INVALID_PROP_NAME : Symbol(INVALID_PROP_NAME, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 12, 33))
>iconProp : Symbol(iconProp, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 12, 61))
// Nested typing works here and we also get an expected error:
const propB2: IProps | number = { nestedProp: { asdfasdf: 'test' }, iconProp: 'test' };
>propB2 : Symbol(propB2, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 15, 5))
>IProps : Symbol(IProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 0, 0))
>nestedProp : Symbol(nestedProp, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 15, 33))
>asdfasdf : Symbol(asdfasdf, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 15, 47))
>iconProp : Symbol(iconProp, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 15, 67))
// Want an error generated here but there isn't one.
const propA1: INestedProps | number = { nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } };
>propA1 : Symbol(propA1, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 18, 5))
>INestedProps : Symbol(INestedProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 5, 1))
>nestedProps : Symbol(nestedProps, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 18, 39))
>INVALID_PROP_NAME : Symbol(INVALID_PROP_NAME, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 18, 54))
>iconProp : Symbol(iconProp, Decl(nonObjectUnionNestedExcessPropertyCheck.ts, 18, 82))

View file

@ -0,0 +1,49 @@
=== tests/cases/compiler/nonObjectUnionNestedExcessPropertyCheck.ts ===
interface IProps {
iconProp?: string;
>iconProp : string
nestedProp?: {
>nestedProp : { testBool?: boolean; }
testBool?: boolean;
>testBool : boolean
}
}
interface INestedProps {
nestedProps?: IProps;
>nestedProps : IProps
}
// These are the types of errors we want:
const propB1: IProps | number = { INVALID_PROP_NAME: 'share', iconProp: 'test' };
>propB1 : number | IProps
>{ INVALID_PROP_NAME: 'share', iconProp: 'test' } : { INVALID_PROP_NAME: string; iconProp: string; }
>INVALID_PROP_NAME : string
>'share' : "share"
>iconProp : string
>'test' : "test"
// Nested typing works here and we also get an expected error:
const propB2: IProps | number = { nestedProp: { asdfasdf: 'test' }, iconProp: 'test' };
>propB2 : number | IProps
>{ nestedProp: { asdfasdf: 'test' }, iconProp: 'test' } : { nestedProp: { asdfasdf: string; }; iconProp: string; }
>nestedProp : { asdfasdf: string; }
>{ asdfasdf: 'test' } : { asdfasdf: string; }
>asdfasdf : string
>'test' : "test"
>iconProp : string
>'test' : "test"
// Want an error generated here but there isn't one.
const propA1: INestedProps | number = { nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } };
>propA1 : number | INestedProps
>{ nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } } : { nestedProps: { INVALID_PROP_NAME: string; iconProp: string; }; }
>nestedProps : { INVALID_PROP_NAME: string; iconProp: string; }
>{ INVALID_PROP_NAME: 'share', iconProp: 'test' } : { INVALID_PROP_NAME: string; iconProp: string; }
>INVALID_PROP_NAME : string
>'share' : "share"
>iconProp : string
>'test' : "test"

View file

@ -0,0 +1,17 @@
//// [unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts]
interface IStringDictionary<V> {
[name: string]: V;
}
interface INumberDictionary<V> {
[idx: number]: V;
}
declare function forEach<T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: () => void) => any);
let count = 0;
forEach({ toString: 123 }, () => count++);
//// [unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.js]
var count = 0;
forEach({ toString: 123 }, function () { return count++; });

View file

@ -0,0 +1,41 @@
=== tests/cases/compiler/unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts ===
interface IStringDictionary<V> {
>IStringDictionary : Symbol(IStringDictionary, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 0, 0))
>V : Symbol(V, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 0, 28))
[name: string]: V;
>name : Symbol(name, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 1, 2))
>V : Symbol(V, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 0, 28))
}
interface INumberDictionary<V> {
>INumberDictionary : Symbol(INumberDictionary, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 2, 1))
>V : Symbol(V, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 3, 28))
[idx: number]: V;
>idx : Symbol(idx, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 4, 2))
>V : Symbol(V, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 3, 28))
}
declare function forEach<T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: () => void) => any);
>forEach : Symbol(forEach, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 5, 1))
>T : Symbol(T, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 25))
>from : Symbol(from, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 28))
>IStringDictionary : Symbol(IStringDictionary, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 0, 0))
>T : Symbol(T, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 25))
>INumberDictionary : Symbol(INumberDictionary, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 2, 1))
>T : Symbol(T, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 25))
>callback : Symbol(callback, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 78))
>entry : Symbol(entry, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 90))
>key : Symbol(key, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 98))
>value : Symbol(value, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 108))
>T : Symbol(T, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 25))
>remove : Symbol(remove, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 7, 121))
let count = 0;
>count : Symbol(count, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 9, 3))
forEach({ toString: 123 }, () => count++);
>forEach : Symbol(forEach, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 5, 1))
>toString : Symbol(toString, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 10, 9))
>count : Symbol(count, Decl(unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts, 9, 3))

View file

@ -0,0 +1,33 @@
=== tests/cases/compiler/unionExcessPropertyCheckNoApparentPropTypeMismatchErrors.ts ===
interface IStringDictionary<V> {
[name: string]: V;
>name : string
}
interface INumberDictionary<V> {
[idx: number]: V;
>idx : number
}
declare function forEach<T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: () => void) => any);
>forEach : <T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: () => void) => any) => any
>from : IStringDictionary<T> | INumberDictionary<T>
>callback : (entry: { key: any; value: T; }, remove: () => void) => any
>entry : { key: any; value: T; }
>key : any
>value : T
>remove : () => void
let count = 0;
>count : number
>0 : 0
forEach({ toString: 123 }, () => count++);
>forEach({ toString: 123 }, () => count++) : any
>forEach : <T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: () => void) => any) => any
>{ toString: 123 } : { toString: number; }
>toString : number
>123 : 123
>() => count++ : () => number
>count++ : number
>count : number

View file

@ -0,0 +1,31 @@
//// [unionExcessPropsWithPartialMember.ts]
interface A {
unused?: string;
x: string;
}
interface B {
x: string;
y: string;
}
declare var ab: A | B;
declare var a: A;
ab = {...a, y: (null as any as string | undefined)}; // Should be allowed, since `y` is missing on `A`
//// [unionExcessPropsWithPartialMember.js]
"use strict";
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);
};
ab = __assign({}, a, { y: null }); // Should be allowed, since `y` is missing on `A`

View file

@ -0,0 +1,35 @@
=== tests/cases/compiler/unionExcessPropsWithPartialMember.ts ===
interface A {
>A : Symbol(A, Decl(unionExcessPropsWithPartialMember.ts, 0, 0))
unused?: string;
>unused : Symbol(A.unused, Decl(unionExcessPropsWithPartialMember.ts, 0, 13))
x: string;
>x : Symbol(A.x, Decl(unionExcessPropsWithPartialMember.ts, 1, 20))
}
interface B {
>B : Symbol(B, Decl(unionExcessPropsWithPartialMember.ts, 3, 1))
x: string;
>x : Symbol(B.x, Decl(unionExcessPropsWithPartialMember.ts, 5, 13))
y: string;
>y : Symbol(B.y, Decl(unionExcessPropsWithPartialMember.ts, 6, 14))
}
declare var ab: A | B;
>ab : Symbol(ab, Decl(unionExcessPropsWithPartialMember.ts, 10, 11))
>A : Symbol(A, Decl(unionExcessPropsWithPartialMember.ts, 0, 0))
>B : Symbol(B, Decl(unionExcessPropsWithPartialMember.ts, 3, 1))
declare var a: A;
>a : Symbol(a, Decl(unionExcessPropsWithPartialMember.ts, 11, 11))
>A : Symbol(A, Decl(unionExcessPropsWithPartialMember.ts, 0, 0))
ab = {...a, y: (null as any as string | undefined)}; // Should be allowed, since `y` is missing on `A`
>ab : Symbol(ab, Decl(unionExcessPropsWithPartialMember.ts, 10, 11))
>a : Symbol(a, Decl(unionExcessPropsWithPartialMember.ts, 11, 11))
>y : Symbol(y, Decl(unionExcessPropsWithPartialMember.ts, 13, 11))

View file

@ -0,0 +1,34 @@
=== tests/cases/compiler/unionExcessPropsWithPartialMember.ts ===
interface A {
unused?: string;
>unused : string | undefined
x: string;
>x : string
}
interface B {
x: string;
>x : string
y: string;
>y : string
}
declare var ab: A | B;
>ab : A | B
declare var a: A;
>a : A
ab = {...a, y: (null as any as string | undefined)}; // Should be allowed, since `y` is missing on `A`
>ab = {...a, y: (null as any as string | undefined)} : { y: string | undefined; unused?: string | undefined; x: string; }
>ab : A | B
>{...a, y: (null as any as string | undefined)} : { y: string | undefined; unused?: string | undefined; x: string; }
>a : A
>y : string | undefined
>(null as any as string | undefined) : string | undefined
>null as any as string | undefined : string | undefined
>null as any : any
>null : null

View file

@ -0,0 +1,27 @@
interface StatelessComponent<P = {}> {
(props: P & { children?: number }, context?: any): null;
}
const TestComponent: StatelessComponent<TestProps> = (props) => {
return null;
}
interface ITestProps {
ariaLabel?: string;
}
interface NestedProp<TProps> {
props: TProps;
}
interface TestProps {
icon: NestedProp<ITestProps>;
}
TestComponent({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});
const TestComponent2: StatelessComponent<TestProps | {props2: {x: number}}> = (props) => {
return null;
}
TestComponent2({icon: { props: { INVALID_PROP_NAME: 'share', ariaLabel: 'test label' } }});

View file

@ -0,0 +1,70 @@
// https://github.com/Microsoft/TypeScript/issues/13813
interface A {
x: string
}
interface B {
a: A;
}
interface C {
c: number;
}
type D = B & C;
let a: B = { a: { x: 'hello' } }; // ok
let b: B = { a: { x: 2 } }; // error - types of property x are incompatible
let c: B = { a: { x: 'hello', y: 2 } }; // error - y does not exist in type A
let d: D = { a: { x: 'hello' }, c: 5 }; // ok
let e: D = { a: { x: 2 }, c: 5 }; // error - types of property x are incompatible
let f: D = { a: { x: 'hello', y: 2 }, c: 5 }; // should be an error
// https://github.com/Microsoft/TypeScript/issues/18075
export type MyType = { id: number; } & { name: string; } & { photo: { id: number; } & { url: string; } }
export let obj: MyType;
export const photo: typeof obj.photo = {
id: 1,
url: '',
xyz: 1 // Great! This causes an error!
};
export const myInstance: MyType = {
id: 1,
name: '',
photo: {
id: 1,
url: '',
xyz: 2 // This should also be an error
}
};
// https://github.com/Microsoft/TypeScript/issues/28616
export type View<T> = { [K in keyof T]: T[K] extends object ? boolean | View<T[K]> : boolean };
interface TypeC {
foo: string;
bar: string;
}
interface TypeB {
foo: string,
bar: TypeC
}
interface TypeA {
foo: string,
bar: TypeB,
}
let test: View<TypeA>;
test = { foo: true, bar: true, boo: true }
test = { foo: true, bar: { foo: true, bar: true, boo: true } }

View file

@ -0,0 +1,19 @@
interface IProps {
iconProp?: string;
nestedProp?: {
testBool?: boolean;
}
}
interface INestedProps {
nestedProps?: IProps;
}
// These are the types of errors we want:
const propB1: IProps | number = { INVALID_PROP_NAME: 'share', iconProp: 'test' };
// Nested typing works here and we also get an expected error:
const propB2: IProps | number = { nestedProp: { asdfasdf: 'test' }, iconProp: 'test' };
// Want an error generated here but there isn't one.
const propA1: INestedProps | number = { nestedProps: { INVALID_PROP_NAME: 'share', iconProp: 'test' } };

View file

@ -0,0 +1,11 @@
interface IStringDictionary<V> {
[name: string]: V;
}
interface INumberDictionary<V> {
[idx: number]: V;
}
declare function forEach<T>(from: IStringDictionary<T> | INumberDictionary<T>, callback: (entry: { key: any; value: T; }, remove: () => void) => any);
let count = 0;
forEach({ toString: 123 }, () => count++);

View file

@ -0,0 +1,15 @@
// @strict: true
interface A {
unused?: string;
x: string;
}
interface B {
x: string;
y: string;
}
declare var ab: A | B;
declare var a: A;
ab = {...a, y: (null as any as string | undefined)}; // Should be allowed, since `y` is missing on `A`