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:
parent
f617d1641b
commit
169e485d90
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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'.
|
||||
|
|
@ -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' } } });
|
|
@ -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))
|
||||
|
|
@ -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"
|
||||
|
|
@ -20,9 +20,7 @@ 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.
|
||||
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'.
|
||||
|
||||
|
@ -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 = {
|
||||
|
|
|
@ -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>'
|
||||
|
|
@ -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 } };
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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'.
|
||||
|
|
@ -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' } };
|
|
@ -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))
|
||||
|
|
@ -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"
|
||||
|
|
@ -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++; });
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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`
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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' } }});
|
|
@ -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 } }
|
|
@ -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' } };
|
|
@ -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++);
|
15
tests/cases/compiler/unionExcessPropsWithPartialMember.ts
Normal file
15
tests/cases/compiler/unionExcessPropsWithPartialMember.ts
Normal 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`
|
Loading…
Reference in a new issue