Skip to content

Commit 0ed9247

Browse files
authored
Explicitly Omit unspreadable properties from rest type in the generic case (#47078)
1 parent 9b5abac commit 0ed9247

File tree

6 files changed

+1067
-7
lines changed

6 files changed

+1067
-7
lines changed

src/compiler/checker.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8464,8 +8464,32 @@ namespace ts {
84648464
if (source.flags & TypeFlags.Union) {
84658465
return mapType(source, t => getRestType(t, properties, symbol));
84668466
}
8467-
const omitKeyType = getUnionType(map(properties, getLiteralTypeFromPropertyName));
8467+
8468+
let omitKeyType = getUnionType(map(properties, getLiteralTypeFromPropertyName));
8469+
8470+
const spreadableProperties: Symbol[] = [];
8471+
const unspreadableToRestKeys: Type[] = [];
8472+
8473+
for (const prop of getPropertiesOfType(source)) {
8474+
const literalTypeFromProperty = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique);
8475+
if (!isTypeAssignableTo(literalTypeFromProperty, omitKeyType)
8476+
&& !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))
8477+
&& isSpreadableProperty(prop)) {
8478+
spreadableProperties.push(prop);
8479+
}
8480+
else {
8481+
unspreadableToRestKeys.push(literalTypeFromProperty);
8482+
}
8483+
}
8484+
84688485
if (isGenericObjectType(source) || isGenericIndexType(omitKeyType)) {
8486+
if (unspreadableToRestKeys.length) {
8487+
// If the type we're spreading from has properties that cannot
8488+
// be spread into the rest type (e.g. getters, methods), ensure
8489+
// they are explicitly omitted, as they would in the non-generic case.
8490+
omitKeyType = getUnionType([omitKeyType, ...unspreadableToRestKeys]);
8491+
}
8492+
84698493
if (omitKeyType.flags & TypeFlags.Never) {
84708494
return source;
84718495
}
@@ -8477,12 +8501,8 @@ namespace ts {
84778501
return getTypeAliasInstantiation(omitTypeAlias, [source, omitKeyType]);
84788502
}
84798503
const members = createSymbolTable();
8480-
for (const prop of getPropertiesOfType(source)) {
8481-
if (!isTypeAssignableTo(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), omitKeyType)
8482-
&& !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected))
8483-
&& isSpreadableProperty(prop)) {
8484-
members.set(prop.escapedName, getSpreadSymbol(prop, /*readonly*/ false));
8485-
}
8504+
for (const prop of spreadableProperties) {
8505+
members.set(prop.escapedName, getSpreadSymbol(prop, /*readonly*/ false));
84868506
}
84878507
const result = createAnonymousType(symbol, members, emptyArray, emptyArray, getIndexInfosOfType(source));
84888508
result.objectFlags |= ObjectFlags.ObjectRestType;
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(22,15): error TS2339: Property 'publicProp' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
2+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(23,15): error TS2339: Property 'publicProp' does not exist on type '{}'.
3+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(25,15): error TS2339: Property 'privateProp' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
4+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(26,15): error TS2339: Property 'privateProp' does not exist on type '{ publicProp: string; }'.
5+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(27,15): error TS2339: Property 'privateProp' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
6+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(28,15): error TS2339: Property 'privateProp' does not exist on type '{}'.
7+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(30,15): error TS2339: Property 'protectedProp' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
8+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(31,15): error TS2339: Property 'protectedProp' does not exist on type '{ publicProp: string; }'.
9+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(32,15): error TS2339: Property 'protectedProp' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
10+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(33,15): error TS2339: Property 'protectedProp' does not exist on type '{}'.
11+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(35,15): error TS2339: Property 'getter' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
12+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(36,15): error TS2339: Property 'getter' does not exist on type '{ publicProp: string; }'.
13+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(37,15): error TS2339: Property 'getter' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
14+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(38,15): error TS2339: Property 'getter' does not exist on type '{}'.
15+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(40,15): error TS2339: Property 'setter' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
16+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(41,15): error TS2339: Property 'setter' does not exist on type '{ publicProp: string; }'.
17+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(42,15): error TS2339: Property 'setter' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
18+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(43,15): error TS2339: Property 'setter' does not exist on type '{}'.
19+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(45,15): error TS2339: Property 'method' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
20+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(46,15): error TS2339: Property 'method' does not exist on type '{ publicProp: string; }'.
21+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(47,15): error TS2339: Property 'method' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
22+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(48,15): error TS2339: Property 'method' does not exist on type '{}'.
23+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(60,11): error TS2339: Property 'publicProp' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
24+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(61,11): error TS2339: Property 'publicProp' does not exist on type '{}'.
25+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(63,11): error TS2339: Property 'privateProp' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
26+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(64,11): error TS2339: Property 'privateProp' does not exist on type '{ publicProp: string; }'.
27+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(65,11): error TS2339: Property 'privateProp' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
28+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(66,11): error TS2339: Property 'privateProp' does not exist on type '{}'.
29+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(68,11): error TS2339: Property 'protectedProp' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
30+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(69,11): error TS2339: Property 'protectedProp' does not exist on type '{ publicProp: string; }'.
31+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(70,11): error TS2339: Property 'protectedProp' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
32+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(71,11): error TS2339: Property 'protectedProp' does not exist on type '{}'.
33+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(73,11): error TS2339: Property 'getter' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
34+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(74,11): error TS2339: Property 'getter' does not exist on type '{ publicProp: string; }'.
35+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(75,11): error TS2339: Property 'getter' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
36+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(76,11): error TS2339: Property 'getter' does not exist on type '{}'.
37+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(78,11): error TS2339: Property 'setter' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
38+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(79,11): error TS2339: Property 'setter' does not exist on type '{ publicProp: string; }'.
39+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(80,11): error TS2339: Property 'setter' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
40+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(81,11): error TS2339: Property 'setter' does not exist on type '{}'.
41+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(83,11): error TS2339: Property 'method' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
42+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(84,11): error TS2339: Property 'method' does not exist on type '{ publicProp: string; }'.
43+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(85,11): error TS2339: Property 'method' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
44+
tests/cases/compiler/destructuringUnspreadableIntoRest.ts(86,11): error TS2339: Property 'method' does not exist on type '{}'.
45+
46+
47+
==== tests/cases/compiler/destructuringUnspreadableIntoRest.ts (44 errors) ====
48+
class A {
49+
constructor(
50+
public publicProp: string,
51+
private privateProp: string,
52+
protected protectedProp: string,
53+
) {}
54+
55+
get getter(): number {
56+
return 1;
57+
}
58+
59+
set setter(_v: number) {}
60+
61+
method() {
62+
const { ...rest1 } = this;
63+
const { ...rest2 } = this as A;
64+
const { publicProp: _1, ...rest3 } = this;
65+
const { publicProp: _2, ...rest4 } = this as A;
66+
67+
rest1.publicProp;
68+
rest2.publicProp;
69+
rest3.publicProp;
70+
~~~~~~~~~~
71+
!!! error TS2339: Property 'publicProp' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
72+
rest4.publicProp;
73+
~~~~~~~~~~
74+
!!! error TS2339: Property 'publicProp' does not exist on type '{}'.
75+
76+
rest1.privateProp;
77+
~~~~~~~~~~~
78+
!!! error TS2339: Property 'privateProp' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
79+
rest2.privateProp;
80+
~~~~~~~~~~~
81+
!!! error TS2339: Property 'privateProp' does not exist on type '{ publicProp: string; }'.
82+
rest3.privateProp;
83+
~~~~~~~~~~~
84+
!!! error TS2339: Property 'privateProp' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
85+
rest4.privateProp;
86+
~~~~~~~~~~~
87+
!!! error TS2339: Property 'privateProp' does not exist on type '{}'.
88+
89+
rest1.protectedProp;
90+
~~~~~~~~~~~~~
91+
!!! error TS2339: Property 'protectedProp' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
92+
rest2.protectedProp;
93+
~~~~~~~~~~~~~
94+
!!! error TS2339: Property 'protectedProp' does not exist on type '{ publicProp: string; }'.
95+
rest3.protectedProp;
96+
~~~~~~~~~~~~~
97+
!!! error TS2339: Property 'protectedProp' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
98+
rest4.protectedProp;
99+
~~~~~~~~~~~~~
100+
!!! error TS2339: Property 'protectedProp' does not exist on type '{}'.
101+
102+
rest1.getter;
103+
~~~~~~
104+
!!! error TS2339: Property 'getter' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
105+
rest2.getter;
106+
~~~~~~
107+
!!! error TS2339: Property 'getter' does not exist on type '{ publicProp: string; }'.
108+
rest3.getter;
109+
~~~~~~
110+
!!! error TS2339: Property 'getter' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
111+
rest4.getter;
112+
~~~~~~
113+
!!! error TS2339: Property 'getter' does not exist on type '{}'.
114+
115+
rest1.setter;
116+
~~~~~~
117+
!!! error TS2339: Property 'setter' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
118+
rest2.setter;
119+
~~~~~~
120+
!!! error TS2339: Property 'setter' does not exist on type '{ publicProp: string; }'.
121+
rest3.setter;
122+
~~~~~~
123+
!!! error TS2339: Property 'setter' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
124+
rest4.setter;
125+
~~~~~~
126+
!!! error TS2339: Property 'setter' does not exist on type '{}'.
127+
128+
rest1.method;
129+
~~~~~~
130+
!!! error TS2339: Property 'method' does not exist on type 'Omit<this, "getter" | "setter" | "method">'.
131+
rest2.method;
132+
~~~~~~
133+
!!! error TS2339: Property 'method' does not exist on type '{ publicProp: string; }'.
134+
rest3.method;
135+
~~~~~~
136+
!!! error TS2339: Property 'method' does not exist on type 'Omit<this, "publicProp" | "getter" | "setter" | "method">'.
137+
rest4.method;
138+
~~~~~~
139+
!!! error TS2339: Property 'method' does not exist on type '{}'.
140+
}
141+
}
142+
143+
function destructure<T extends A>(x: T) {
144+
const { ...rest1 } = x;
145+
const { ...rest2 } = x as A;
146+
const { publicProp: _1, ...rest3 } = x;
147+
const { publicProp: _2, ...rest4 } = x as A;
148+
149+
rest1.publicProp;
150+
rest2.publicProp;
151+
rest3.publicProp;
152+
~~~~~~~~~~
153+
!!! error TS2339: Property 'publicProp' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
154+
rest4.publicProp;
155+
~~~~~~~~~~
156+
!!! error TS2339: Property 'publicProp' does not exist on type '{}'.
157+
158+
rest1.privateProp;
159+
~~~~~~~~~~~
160+
!!! error TS2339: Property 'privateProp' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
161+
rest2.privateProp;
162+
~~~~~~~~~~~
163+
!!! error TS2339: Property 'privateProp' does not exist on type '{ publicProp: string; }'.
164+
rest3.privateProp;
165+
~~~~~~~~~~~
166+
!!! error TS2339: Property 'privateProp' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
167+
rest4.privateProp;
168+
~~~~~~~~~~~
169+
!!! error TS2339: Property 'privateProp' does not exist on type '{}'.
170+
171+
rest1.protectedProp;
172+
~~~~~~~~~~~~~
173+
!!! error TS2339: Property 'protectedProp' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
174+
rest2.protectedProp;
175+
~~~~~~~~~~~~~
176+
!!! error TS2339: Property 'protectedProp' does not exist on type '{ publicProp: string; }'.
177+
rest3.protectedProp;
178+
~~~~~~~~~~~~~
179+
!!! error TS2339: Property 'protectedProp' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
180+
rest4.protectedProp;
181+
~~~~~~~~~~~~~
182+
!!! error TS2339: Property 'protectedProp' does not exist on type '{}'.
183+
184+
rest1.getter;
185+
~~~~~~
186+
!!! error TS2339: Property 'getter' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
187+
rest2.getter;
188+
~~~~~~
189+
!!! error TS2339: Property 'getter' does not exist on type '{ publicProp: string; }'.
190+
rest3.getter;
191+
~~~~~~
192+
!!! error TS2339: Property 'getter' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
193+
rest4.getter;
194+
~~~~~~
195+
!!! error TS2339: Property 'getter' does not exist on type '{}'.
196+
197+
rest1.setter;
198+
~~~~~~
199+
!!! error TS2339: Property 'setter' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
200+
rest2.setter;
201+
~~~~~~
202+
!!! error TS2339: Property 'setter' does not exist on type '{ publicProp: string; }'.
203+
rest3.setter;
204+
~~~~~~
205+
!!! error TS2339: Property 'setter' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
206+
rest4.setter;
207+
~~~~~~
208+
!!! error TS2339: Property 'setter' does not exist on type '{}'.
209+
210+
rest1.method;
211+
~~~~~~
212+
!!! error TS2339: Property 'method' does not exist on type 'Omit<T, "getter" | "setter" | "method">'.
213+
rest2.method;
214+
~~~~~~
215+
!!! error TS2339: Property 'method' does not exist on type '{ publicProp: string; }'.
216+
rest3.method;
217+
~~~~~~
218+
!!! error TS2339: Property 'method' does not exist on type 'Omit<T, "publicProp" | "getter" | "setter" | "method">'.
219+
rest4.method;
220+
~~~~~~
221+
!!! error TS2339: Property 'method' does not exist on type '{}'.
222+
}
223+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy