Skip to content

Commit 520772e

Browse files
authored
Fixed excess and common property checks with NoInfer (microsoft#57673)
1 parent 824cd6e commit 520772e

9 files changed

+486
-1
lines changed

src/compiler/checker.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -23971,6 +23971,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2397123971
return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 && resolved.indexInfos.length === 0 &&
2397223972
resolved.properties.length > 0 && every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional));
2397323973
}
23974+
if (type.flags & TypeFlags.Substitution) {
23975+
return isWeakType((type as SubstitutionType).baseType);
23976+
}
2397423977
if (type.flags & TypeFlags.Intersection) {
2397523978
return every((type as IntersectionType).types, isWeakType);
2397623979
}
@@ -32717,7 +32720,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3271732720
return true;
3271832721
}
3271932722
}
32720-
else if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType)) {
32723+
if (targetType.flags & TypeFlags.Substitution) {
32724+
return isKnownProperty((targetType as SubstitutionType).baseType, name, isComparingJsxAttributes);
32725+
}
32726+
if (targetType.flags & TypeFlags.UnionOrIntersection && isExcessPropertyCheckTarget(targetType)) {
3272132727
for (const t of (targetType as UnionOrIntersectionType).types) {
3272232728
if (isKnownProperty(t, name, isComparingJsxAttributes)) {
3272332729
return true;
@@ -32730,6 +32736,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3273032736
function isExcessPropertyCheckTarget(type: Type): boolean {
3273132737
return !!(type.flags & TypeFlags.Object && !(getObjectFlags(type) & ObjectFlags.ObjectLiteralPatternWithComputedProperties) ||
3273232738
type.flags & TypeFlags.NonPrimitive ||
32739+
type.flags & TypeFlags.Substitution && isExcessPropertyCheckTarget((type as SubstitutionType).baseType) ||
3273332740
type.flags & TypeFlags.Union && some((type as UnionType).types, isExcessPropertyCheckTarget) ||
3273432741
type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isExcessPropertyCheckTarget));
3273532742
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
noInferCommonPropertyCheck1.ts(7,20): error TS2559: Type '{ x: string; }' has no properties in common with type 'NoInfer<Partial<{ a: unknown; b: unknown; }>> & { prop?: unknown; }'.
2+
noInferCommonPropertyCheck1.ts(15,33): error TS2559: Type '{ x: string; }' has no properties in common with type 'NoInfer<Partial<{ a: unknown; b: unknown; }>> & NoInfer<Partial<{ c: unknown; d: unknown; }>>'.
3+
noInferCommonPropertyCheck1.ts(23,33): error TS2559: Type '{ x: string; }' has no properties in common with type 'Partial<{ a: unknown; b: unknown; }> & Partial<{ c: unknown; d: unknown; }>'.
4+
5+
6+
==== noInferCommonPropertyCheck1.ts (3 errors) ====
7+
declare const partialObj1: Partial<{ a: unknown; b: unknown }>;
8+
declare const partialObj2: Partial<{ c: unknown; d: unknown }>;
9+
declare const someObj1: { x: string };
10+
11+
declare function test1<T>(a: T, b: NoInfer<T> & { prop?: unknown }): void;
12+
13+
test1(partialObj1, someObj1);
14+
~~~~~~~~
15+
!!! error TS2559: Type '{ x: string; }' has no properties in common with type 'NoInfer<Partial<{ a: unknown; b: unknown; }>> & { prop?: unknown; }'.
16+
17+
declare function test2<T1, T2>(
18+
a: T1,
19+
b: T2,
20+
c: NoInfer<T1> & NoInfer<T2>,
21+
): void;
22+
23+
test2(partialObj1, partialObj2, someObj1);
24+
~~~~~~~~
25+
!!! error TS2559: Type '{ x: string; }' has no properties in common with type 'NoInfer<Partial<{ a: unknown; b: unknown; }>> & NoInfer<Partial<{ c: unknown; d: unknown; }>>'.
26+
27+
declare function test3<T1, T2>(
28+
a: T1,
29+
b: T2,
30+
c: NoInfer<T1 & T2>,
31+
): void;
32+
33+
test3(partialObj1, partialObj2, someObj1);
34+
~~~~~~~~
35+
!!! error TS2559: Type '{ x: string; }' has no properties in common with type 'Partial<{ a: unknown; b: unknown; }> & Partial<{ c: unknown; d: unknown; }>'.
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//// [tests/cases/compiler/noInferCommonPropertyCheck1.ts] ////
2+
3+
=== noInferCommonPropertyCheck1.ts ===
4+
declare const partialObj1: Partial<{ a: unknown; b: unknown }>;
5+
>partialObj1 : Symbol(partialObj1, Decl(noInferCommonPropertyCheck1.ts, 0, 13))
6+
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
7+
>a : Symbol(a, Decl(noInferCommonPropertyCheck1.ts, 0, 36))
8+
>b : Symbol(b, Decl(noInferCommonPropertyCheck1.ts, 0, 48))
9+
10+
declare const partialObj2: Partial<{ c: unknown; d: unknown }>;
11+
>partialObj2 : Symbol(partialObj2, Decl(noInferCommonPropertyCheck1.ts, 1, 13))
12+
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
13+
>c : Symbol(c, Decl(noInferCommonPropertyCheck1.ts, 1, 36))
14+
>d : Symbol(d, Decl(noInferCommonPropertyCheck1.ts, 1, 48))
15+
16+
declare const someObj1: { x: string };
17+
>someObj1 : Symbol(someObj1, Decl(noInferCommonPropertyCheck1.ts, 2, 13))
18+
>x : Symbol(x, Decl(noInferCommonPropertyCheck1.ts, 2, 25))
19+
20+
declare function test1<T>(a: T, b: NoInfer<T> & { prop?: unknown }): void;
21+
>test1 : Symbol(test1, Decl(noInferCommonPropertyCheck1.ts, 2, 38))
22+
>T : Symbol(T, Decl(noInferCommonPropertyCheck1.ts, 4, 23))
23+
>a : Symbol(a, Decl(noInferCommonPropertyCheck1.ts, 4, 26))
24+
>T : Symbol(T, Decl(noInferCommonPropertyCheck1.ts, 4, 23))
25+
>b : Symbol(b, Decl(noInferCommonPropertyCheck1.ts, 4, 31))
26+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
27+
>T : Symbol(T, Decl(noInferCommonPropertyCheck1.ts, 4, 23))
28+
>prop : Symbol(prop, Decl(noInferCommonPropertyCheck1.ts, 4, 49))
29+
30+
test1(partialObj1, someObj1);
31+
>test1 : Symbol(test1, Decl(noInferCommonPropertyCheck1.ts, 2, 38))
32+
>partialObj1 : Symbol(partialObj1, Decl(noInferCommonPropertyCheck1.ts, 0, 13))
33+
>someObj1 : Symbol(someObj1, Decl(noInferCommonPropertyCheck1.ts, 2, 13))
34+
35+
declare function test2<T1, T2>(
36+
>test2 : Symbol(test2, Decl(noInferCommonPropertyCheck1.ts, 6, 29))
37+
>T1 : Symbol(T1, Decl(noInferCommonPropertyCheck1.ts, 8, 23))
38+
>T2 : Symbol(T2, Decl(noInferCommonPropertyCheck1.ts, 8, 26))
39+
40+
a: T1,
41+
>a : Symbol(a, Decl(noInferCommonPropertyCheck1.ts, 8, 31))
42+
>T1 : Symbol(T1, Decl(noInferCommonPropertyCheck1.ts, 8, 23))
43+
44+
b: T2,
45+
>b : Symbol(b, Decl(noInferCommonPropertyCheck1.ts, 9, 8))
46+
>T2 : Symbol(T2, Decl(noInferCommonPropertyCheck1.ts, 8, 26))
47+
48+
c: NoInfer<T1> & NoInfer<T2>,
49+
>c : Symbol(c, Decl(noInferCommonPropertyCheck1.ts, 10, 8))
50+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
51+
>T1 : Symbol(T1, Decl(noInferCommonPropertyCheck1.ts, 8, 23))
52+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
53+
>T2 : Symbol(T2, Decl(noInferCommonPropertyCheck1.ts, 8, 26))
54+
55+
): void;
56+
57+
test2(partialObj1, partialObj2, someObj1);
58+
>test2 : Symbol(test2, Decl(noInferCommonPropertyCheck1.ts, 6, 29))
59+
>partialObj1 : Symbol(partialObj1, Decl(noInferCommonPropertyCheck1.ts, 0, 13))
60+
>partialObj2 : Symbol(partialObj2, Decl(noInferCommonPropertyCheck1.ts, 1, 13))
61+
>someObj1 : Symbol(someObj1, Decl(noInferCommonPropertyCheck1.ts, 2, 13))
62+
63+
declare function test3<T1, T2>(
64+
>test3 : Symbol(test3, Decl(noInferCommonPropertyCheck1.ts, 14, 42))
65+
>T1 : Symbol(T1, Decl(noInferCommonPropertyCheck1.ts, 16, 23))
66+
>T2 : Symbol(T2, Decl(noInferCommonPropertyCheck1.ts, 16, 26))
67+
68+
a: T1,
69+
>a : Symbol(a, Decl(noInferCommonPropertyCheck1.ts, 16, 31))
70+
>T1 : Symbol(T1, Decl(noInferCommonPropertyCheck1.ts, 16, 23))
71+
72+
b: T2,
73+
>b : Symbol(b, Decl(noInferCommonPropertyCheck1.ts, 17, 8))
74+
>T2 : Symbol(T2, Decl(noInferCommonPropertyCheck1.ts, 16, 26))
75+
76+
c: NoInfer<T1 & T2>,
77+
>c : Symbol(c, Decl(noInferCommonPropertyCheck1.ts, 18, 8))
78+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
79+
>T1 : Symbol(T1, Decl(noInferCommonPropertyCheck1.ts, 16, 23))
80+
>T2 : Symbol(T2, Decl(noInferCommonPropertyCheck1.ts, 16, 26))
81+
82+
): void;
83+
84+
test3(partialObj1, partialObj2, someObj1);
85+
>test3 : Symbol(test3, Decl(noInferCommonPropertyCheck1.ts, 14, 42))
86+
>partialObj1 : Symbol(partialObj1, Decl(noInferCommonPropertyCheck1.ts, 0, 13))
87+
>partialObj2 : Symbol(partialObj2, Decl(noInferCommonPropertyCheck1.ts, 1, 13))
88+
>someObj1 : Symbol(someObj1, Decl(noInferCommonPropertyCheck1.ts, 2, 13))
89+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//// [tests/cases/compiler/noInferCommonPropertyCheck1.ts] ////
2+
3+
=== noInferCommonPropertyCheck1.ts ===
4+
declare const partialObj1: Partial<{ a: unknown; b: unknown }>;
5+
>partialObj1 : Partial<{ a: unknown; b: unknown; }>
6+
>a : unknown
7+
>b : unknown
8+
9+
declare const partialObj2: Partial<{ c: unknown; d: unknown }>;
10+
>partialObj2 : Partial<{ c: unknown; d: unknown; }>
11+
>c : unknown
12+
>d : unknown
13+
14+
declare const someObj1: { x: string };
15+
>someObj1 : { x: string; }
16+
>x : string
17+
18+
declare function test1<T>(a: T, b: NoInfer<T> & { prop?: unknown }): void;
19+
>test1 : <T>(a: T, b: NoInfer<T> & { prop?: unknown;}) => void
20+
>a : T
21+
>b : NoInfer<T> & { prop?: unknown; }
22+
>prop : unknown
23+
24+
test1(partialObj1, someObj1);
25+
>test1(partialObj1, someObj1) : void
26+
>test1 : <T>(a: T, b: NoInfer<T> & { prop?: unknown; }) => void
27+
>partialObj1 : Partial<{ a: unknown; b: unknown; }>
28+
>someObj1 : { x: string; }
29+
30+
declare function test2<T1, T2>(
31+
>test2 : <T1, T2>(a: T1, b: T2, c: NoInfer<T1> & NoInfer<T2>) => void
32+
33+
a: T1,
34+
>a : T1
35+
36+
b: T2,
37+
>b : T2
38+
39+
c: NoInfer<T1> & NoInfer<T2>,
40+
>c : NoInfer<T1> & NoInfer<T2>
41+
42+
): void;
43+
44+
test2(partialObj1, partialObj2, someObj1);
45+
>test2(partialObj1, partialObj2, someObj1) : void
46+
>test2 : <T1, T2>(a: T1, b: T2, c: NoInfer<T1> & NoInfer<T2>) => void
47+
>partialObj1 : Partial<{ a: unknown; b: unknown; }>
48+
>partialObj2 : Partial<{ c: unknown; d: unknown; }>
49+
>someObj1 : { x: string; }
50+
51+
declare function test3<T1, T2>(
52+
>test3 : <T1, T2>(a: T1, b: T2, c: NoInfer<T1 & T2>) => void
53+
54+
a: T1,
55+
>a : T1
56+
57+
b: T2,
58+
>b : T2
59+
60+
c: NoInfer<T1 & T2>,
61+
>c : NoInfer<T1 & T2>
62+
63+
): void;
64+
65+
test3(partialObj1, partialObj2, someObj1);
66+
>test3(partialObj1, partialObj2, someObj1) : void
67+
>test3 : <T1, T2>(a: T1, b: T2, c: NoInfer<T1 & T2>) => void
68+
>partialObj1 : Partial<{ a: unknown; b: unknown; }>
69+
>partialObj2 : Partial<{ c: unknown; d: unknown; }>
70+
>someObj1 : { x: string; }
71+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
noInferUnionExcessPropertyCheck1.ts(7,33): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type 'NoInfer<{ x: string; }> | (() => NoInfer<{ x: string; }>)'.
2+
noInferUnionExcessPropertyCheck1.ts(15,33): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type 'NoInfer<{ x: string; }> | NoInfer<() => { x: string; }>'.
3+
noInferUnionExcessPropertyCheck1.ts(23,33): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: string; } | (() => { x: string; })'.
4+
5+
6+
==== noInferUnionExcessPropertyCheck1.ts (3 errors) ====
7+
declare function test1<T extends { x: string }>(
8+
a: T,
9+
b: NoInfer<T> | (() => NoInfer<T>),
10+
): void;
11+
12+
test1({ x: "foo" }, { x: "bar" }); // no error
13+
test1({ x: "foo" }, { x: "bar", y: 42 }); // epc error
14+
~
15+
!!! error TS2353: Object literal may only specify known properties, and 'y' does not exist in type 'NoInfer<{ x: string; }> | (() => NoInfer<{ x: string; }>)'.
16+
17+
declare function test2<T extends { x: string }>(
18+
a: T,
19+
b: NoInfer<T> | NoInfer<() => T>,
20+
): void;
21+
22+
test2({ x: "foo" }, { x: "bar" }); // no error
23+
test2({ x: "foo" }, { x: "bar", y: 42 }); // epc error
24+
~
25+
!!! error TS2353: Object literal may only specify known properties, and 'y' does not exist in type 'NoInfer<{ x: string; }> | NoInfer<() => { x: string; }>'.
26+
27+
declare function test3<T extends { x: string }>(
28+
a: T,
29+
b: NoInfer<T | (() => T)>,
30+
): void;
31+
32+
test3({ x: "foo" }, { x: "bar" }); // no error
33+
test3({ x: "foo" }, { x: "bar", y: 42 }); // epc error
34+
~
35+
!!! error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: string; } | (() => { x: string; })'.
36+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//// [tests/cases/compiler/noInferUnionExcessPropertyCheck1.ts] ////
2+
3+
=== noInferUnionExcessPropertyCheck1.ts ===
4+
declare function test1<T extends { x: string }>(
5+
>test1 : Symbol(test1, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 0))
6+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 23))
7+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 34))
8+
9+
a: T,
10+
>a : Symbol(a, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 48))
11+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 23))
12+
13+
b: NoInfer<T> | (() => NoInfer<T>),
14+
>b : Symbol(b, Decl(noInferUnionExcessPropertyCheck1.ts, 1, 7))
15+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
16+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 23))
17+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
18+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 23))
19+
20+
): void;
21+
22+
test1({ x: "foo" }, { x: "bar" }); // no error
23+
>test1 : Symbol(test1, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 0))
24+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 5, 7))
25+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 5, 21))
26+
27+
test1({ x: "foo" }, { x: "bar", y: 42 }); // epc error
28+
>test1 : Symbol(test1, Decl(noInferUnionExcessPropertyCheck1.ts, 0, 0))
29+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 6, 7))
30+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 6, 21))
31+
>y : Symbol(y, Decl(noInferUnionExcessPropertyCheck1.ts, 6, 31))
32+
33+
declare function test2<T extends { x: string }>(
34+
>test2 : Symbol(test2, Decl(noInferUnionExcessPropertyCheck1.ts, 6, 41))
35+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 8, 23))
36+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 8, 34))
37+
38+
a: T,
39+
>a : Symbol(a, Decl(noInferUnionExcessPropertyCheck1.ts, 8, 48))
40+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 8, 23))
41+
42+
b: NoInfer<T> | NoInfer<() => T>,
43+
>b : Symbol(b, Decl(noInferUnionExcessPropertyCheck1.ts, 9, 7))
44+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
45+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 8, 23))
46+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
47+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 8, 23))
48+
49+
): void;
50+
51+
test2({ x: "foo" }, { x: "bar" }); // no error
52+
>test2 : Symbol(test2, Decl(noInferUnionExcessPropertyCheck1.ts, 6, 41))
53+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 13, 7))
54+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 13, 21))
55+
56+
test2({ x: "foo" }, { x: "bar", y: 42 }); // epc error
57+
>test2 : Symbol(test2, Decl(noInferUnionExcessPropertyCheck1.ts, 6, 41))
58+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 14, 7))
59+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 14, 21))
60+
>y : Symbol(y, Decl(noInferUnionExcessPropertyCheck1.ts, 14, 31))
61+
62+
declare function test3<T extends { x: string }>(
63+
>test3 : Symbol(test3, Decl(noInferUnionExcessPropertyCheck1.ts, 14, 41))
64+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 16, 23))
65+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 16, 34))
66+
67+
a: T,
68+
>a : Symbol(a, Decl(noInferUnionExcessPropertyCheck1.ts, 16, 48))
69+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 16, 23))
70+
71+
b: NoInfer<T | (() => T)>,
72+
>b : Symbol(b, Decl(noInferUnionExcessPropertyCheck1.ts, 17, 7))
73+
>NoInfer : Symbol(NoInfer, Decl(lib.es5.d.ts, --, --))
74+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 16, 23))
75+
>T : Symbol(T, Decl(noInferUnionExcessPropertyCheck1.ts, 16, 23))
76+
77+
): void;
78+
79+
test3({ x: "foo" }, { x: "bar" }); // no error
80+
>test3 : Symbol(test3, Decl(noInferUnionExcessPropertyCheck1.ts, 14, 41))
81+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 21, 7))
82+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 21, 21))
83+
84+
test3({ x: "foo" }, { x: "bar", y: 42 }); // epc error
85+
>test3 : Symbol(test3, Decl(noInferUnionExcessPropertyCheck1.ts, 14, 41))
86+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 22, 7))
87+
>x : Symbol(x, Decl(noInferUnionExcessPropertyCheck1.ts, 22, 21))
88+
>y : Symbol(y, Decl(noInferUnionExcessPropertyCheck1.ts, 22, 31))
89+

0 commit comments

Comments
 (0)