Skip to content

Commit 7fdfcf1

Browse files
committed
Add test to verify use of Pick<T, K> with setState
1 parent 00f7d85 commit 7fdfcf1

File tree

3 files changed

+192
-4
lines changed

3 files changed

+192
-4
lines changed

tests/baselines/reference/mappedTypeErrors.errors.txt

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,19 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(78,59): error TS2345: A
2626
Object literal may only specify known properties, and 'z' does not exist in type 'Readonly<{ x: number; y: number; }>'.
2727
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(84,58): error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Partial<{ x: number; y: number; }>'.
2828
Object literal may only specify known properties, and 'z' does not exist in type 'Partial<{ x: number; y: number; }>'.
29+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(106,15): error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick<Foo, "a">'.
30+
Types of property 'a' are incompatible.
31+
Type 'undefined' is not assignable to type 'string'.
32+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(107,17): error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick<Foo, "a" | "b">'.
33+
Object literal may only specify known properties, and 'c' does not exist in type 'Pick<Foo, "a" | "b">'.
34+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(124,12): error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick<Foo, "a">'.
35+
Types of property 'a' are incompatible.
36+
Type 'undefined' is not assignable to type 'string'.
37+
tests/cases/conformance/types/mapped/mappedTypeErrors.ts(125,14): error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick<Foo, "a" | "b">'.
38+
Object literal may only specify known properties, and 'c' does not exist in type 'Pick<Foo, "a" | "b">'.
2939

3040

31-
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (17 errors) ====
41+
==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (21 errors) ====
3242

3343
interface Shape {
3444
name: string;
@@ -158,4 +168,59 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(84,58): error TS2345: A
158168
~~~~
159169
!!! error TS2345: Argument of type '{ x: number; y: number; z: number; }' is not assignable to parameter of type 'Partial<{ x: number; y: number; }>'.
160170
!!! error TS2345: Object literal may only specify known properties, and 'z' does not exist in type 'Partial<{ x: number; y: number; }>'.
161-
}
171+
}
172+
173+
// Verify use of Pick<T, K> for setState functions (#12793)
174+
175+
interface Foo {
176+
a: string;
177+
b?: number;
178+
}
179+
180+
function setState<T, K extends keyof T>(obj: T, props: Pick<T, K>) {
181+
for (let k in props) {
182+
obj[k] = props[k];
183+
}
184+
}
185+
186+
let foo: Foo = { a: "hello", b: 42 };
187+
setState(foo, { a: "test", b: 43 })
188+
setState(foo, { a: "hi" });
189+
setState(foo, { b: undefined });
190+
setState(foo, { });
191+
setState(foo, foo);
192+
setState(foo, { a: undefined }); // Error
193+
~~~~~~~~~~~~~~~~
194+
!!! error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick<Foo, "a">'.
195+
!!! error TS2345: Types of property 'a' are incompatible.
196+
!!! error TS2345: Type 'undefined' is not assignable to type 'string'.
197+
setState(foo, { c: true }); // Error
198+
~~~~~~~
199+
!!! error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick<Foo, "a" | "b">'.
200+
!!! error TS2345: Object literal may only specify known properties, and 'c' does not exist in type 'Pick<Foo, "a" | "b">'.
201+
202+
class C<T> {
203+
state: T;
204+
setState<K extends keyof T>(props: Pick<T, K>) {
205+
for (let k in props) {
206+
this.state[k] = props[k];
207+
}
208+
}
209+
}
210+
211+
let c = new C<Foo>();
212+
c.setState({ a: "test", b: 43 });
213+
c.setState({ a: "hi" });
214+
c.setState({ b: undefined });
215+
c.setState({ });
216+
c.setState(foo);
217+
c.setState({ a: undefined }); // Error
218+
~~~~~~~~~~~~~~~~
219+
!!! error TS2345: Argument of type '{ a: undefined; }' is not assignable to parameter of type 'Pick<Foo, "a">'.
220+
!!! error TS2345: Types of property 'a' are incompatible.
221+
!!! error TS2345: Type 'undefined' is not assignable to type 'string'.
222+
c.setState({ c: true }); // Error
223+
~~~~~~~
224+
!!! error TS2345: Argument of type '{ c: boolean; }' is not assignable to parameter of type 'Pick<Foo, "a" | "b">'.
225+
!!! error TS2345: Object literal may only specify known properties, and 'c' does not exist in type 'Pick<Foo, "a" | "b">'.
226+

tests/baselines/reference/mappedTypeErrors.js

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,48 @@ function f21() {
8383
let x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 });
8484
let x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 });
8585
let x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
86-
}
86+
}
87+
88+
// Verify use of Pick<T, K> for setState functions (#12793)
89+
90+
interface Foo {
91+
a: string;
92+
b?: number;
93+
}
94+
95+
function setState<T, K extends keyof T>(obj: T, props: Pick<T, K>) {
96+
for (let k in props) {
97+
obj[k] = props[k];
98+
}
99+
}
100+
101+
let foo: Foo = { a: "hello", b: 42 };
102+
setState(foo, { a: "test", b: 43 })
103+
setState(foo, { a: "hi" });
104+
setState(foo, { b: undefined });
105+
setState(foo, { });
106+
setState(foo, foo);
107+
setState(foo, { a: undefined }); // Error
108+
setState(foo, { c: true }); // Error
109+
110+
class C<T> {
111+
state: T;
112+
setState<K extends keyof T>(props: Pick<T, K>) {
113+
for (let k in props) {
114+
this.state[k] = props[k];
115+
}
116+
}
117+
}
118+
119+
let c = new C<Foo>();
120+
c.setState({ a: "test", b: 43 });
121+
c.setState({ a: "hi" });
122+
c.setState({ b: undefined });
123+
c.setState({ });
124+
c.setState(foo);
125+
c.setState({ a: undefined }); // Error
126+
c.setState({ c: true }); // Error
127+
87128

88129
//// [mappedTypeErrors.js]
89130
function f1(x) {
@@ -124,6 +165,37 @@ function f21() {
124165
var x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 });
125166
var x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
126167
}
168+
function setState(obj, props) {
169+
for (var k in props) {
170+
obj[k] = props[k];
171+
}
172+
}
173+
var foo = { a: "hello", b: 42 };
174+
setState(foo, { a: "test", b: 43 });
175+
setState(foo, { a: "hi" });
176+
setState(foo, { b: undefined });
177+
setState(foo, {});
178+
setState(foo, foo);
179+
setState(foo, { a: undefined }); // Error
180+
setState(foo, { c: true }); // Error
181+
var C = (function () {
182+
function C() {
183+
}
184+
C.prototype.setState = function (props) {
185+
for (var k in props) {
186+
this.state[k] = props[k];
187+
}
188+
};
189+
return C;
190+
}());
191+
var c = new C();
192+
c.setState({ a: "test", b: 43 });
193+
c.setState({ a: "hi" });
194+
c.setState({ b: undefined });
195+
c.setState({});
196+
c.setState(foo);
197+
c.setState({ a: undefined }); // Error
198+
c.setState({ c: true }); // Error
127199

128200

129201
//// [mappedTypeErrors.d.ts]
@@ -168,3 +240,14 @@ declare function objAndReadonly<T>(primary: T, secondary: Readonly<T>): T;
168240
declare function objAndPartial<T>(primary: T, secondary: Partial<T>): T;
169241
declare function f20(): void;
170242
declare function f21(): void;
243+
interface Foo {
244+
a: string;
245+
b?: number;
246+
}
247+
declare function setState<T, K extends keyof T>(obj: T, props: Pick<T, K>): void;
248+
declare let foo: Foo;
249+
declare class C<T> {
250+
state: T;
251+
setState<K extends keyof T>(props: Pick<T, K>): void;
252+
}
253+
declare let c: C<Foo>;

tests/cases/conformance/types/mapped/mappedTypeErrors.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,44 @@ function f21() {
8484
let x1 = objAndPartial({ x: 0, y: 0 }, { x: 1 });
8585
let x2 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1 });
8686
let x3 = objAndPartial({ x: 0, y: 0 }, { x: 1, y: 1, z: 1 }); // Error
87-
}
87+
}
88+
89+
// Verify use of Pick<T, K> for setState functions (#12793)
90+
91+
interface Foo {
92+
a: string;
93+
b?: number;
94+
}
95+
96+
function setState<T, K extends keyof T>(obj: T, props: Pick<T, K>) {
97+
for (let k in props) {
98+
obj[k] = props[k];
99+
}
100+
}
101+
102+
let foo: Foo = { a: "hello", b: 42 };
103+
setState(foo, { a: "test", b: 43 })
104+
setState(foo, { a: "hi" });
105+
setState(foo, { b: undefined });
106+
setState(foo, { });
107+
setState(foo, foo);
108+
setState(foo, { a: undefined }); // Error
109+
setState(foo, { c: true }); // Error
110+
111+
class C<T> {
112+
state: T;
113+
setState<K extends keyof T>(props: Pick<T, K>) {
114+
for (let k in props) {
115+
this.state[k] = props[k];
116+
}
117+
}
118+
}
119+
120+
let c = new C<Foo>();
121+
c.setState({ a: "test", b: 43 });
122+
c.setState({ a: "hi" });
123+
c.setState({ b: undefined });
124+
c.setState({ });
125+
c.setState(foo);
126+
c.setState({ a: undefined }); // Error
127+
c.setState({ c: true }); // Error

0 commit comments

Comments
 (0)