Skip to content

Commit 45a6cb7

Browse files
authored
Reset toplevel flag when higher priority inference takes place (microsoft#30265)
1 parent d59e51b commit 45a6cb7

6 files changed

+301
-0
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14500,6 +14500,7 @@ namespace ts {
1450014500
if (inference.priority === undefined || priority < inference.priority) {
1450114501
inference.candidates = undefined;
1450214502
inference.contraCandidates = undefined;
14503+
inference.topLevel = true;
1450314504
inference.priority = priority;
1450414505
}
1450514506
if (priority === inference.priority) {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
tests/cases/compiler/paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts(27,23): error TS2345: Argument of type '{ x?: number[] | undefined; y?: string[] | undefined; }' is not assignable to parameter of type '{ y?: number[] | undefined; }'.
2+
Types of property 'y' are incompatible.
3+
Type 'string[] | undefined' is not assignable to type 'number[] | undefined'.
4+
Type 'string[]' is not assignable to type 'number[]'.
5+
Type 'string' is not assignable to type 'number'.
6+
tests/cases/compiler/paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts(28,23): error TS2345: Argument of type '{ x?: number[] | undefined; y?: string[] | undefined; }' is not assignable to parameter of type '{ x?: string[] | undefined; }'.
7+
Types of property 'x' are incompatible.
8+
Type 'number[] | undefined' is not assignable to type 'string[] | undefined'.
9+
Type 'number[]' is not assignable to type 'string[]'.
10+
Type 'number' is not assignable to type 'string'.
11+
12+
13+
==== tests/cases/compiler/paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts (2 errors) ====
14+
// Using a homomorphic mapped type over `T`
15+
// Produces a lower-priority inference for `T` than other
16+
// positions, allowing one to override the priority the argument
17+
// order would usually imply
18+
type Lower<T> = { [K in keyof T]: T[K] };
19+
20+
export function appendToOptionalArray<
21+
K extends string | number | symbol,
22+
T
23+
>(
24+
object: { [x in K]?: Lower<T>[] },
25+
key: K,
26+
value: T
27+
) {
28+
const array = object[key];
29+
if (array) {
30+
array.push(value);
31+
} else {
32+
object[key] = [value];
33+
}
34+
}
35+
36+
// e.g.
37+
const foo: {x?: number[]; y?: string[]; } = {};
38+
appendToOptionalArray(foo, 'x', 123); // ok
39+
appendToOptionalArray(foo, 'y', 'bar'); // ok
40+
appendToOptionalArray(foo, 'y', 12); // should fail
41+
~~~
42+
!!! error TS2345: Argument of type '{ x?: number[] | undefined; y?: string[] | undefined; }' is not assignable to parameter of type '{ y?: number[] | undefined; }'.
43+
!!! error TS2345: Types of property 'y' are incompatible.
44+
!!! error TS2345: Type 'string[] | undefined' is not assignable to type 'number[] | undefined'.
45+
!!! error TS2345: Type 'string[]' is not assignable to type 'number[]'.
46+
!!! error TS2345: Type 'string' is not assignable to type 'number'.
47+
appendToOptionalArray(foo, 'x', "no"); // should fail
48+
~~~
49+
!!! error TS2345: Argument of type '{ x?: number[] | undefined; y?: string[] | undefined; }' is not assignable to parameter of type '{ x?: string[] | undefined; }'.
50+
!!! error TS2345: Types of property 'x' are incompatible.
51+
!!! error TS2345: Type 'number[] | undefined' is not assignable to type 'string[] | undefined'.
52+
!!! error TS2345: Type 'number[]' is not assignable to type 'string[]'.
53+
!!! error TS2345: Type 'number' is not assignable to type 'string'.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//// [paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts]
2+
// Using a homomorphic mapped type over `T`
3+
// Produces a lower-priority inference for `T` than other
4+
// positions, allowing one to override the priority the argument
5+
// order would usually imply
6+
type Lower<T> = { [K in keyof T]: T[K] };
7+
8+
export function appendToOptionalArray<
9+
K extends string | number | symbol,
10+
T
11+
>(
12+
object: { [x in K]?: Lower<T>[] },
13+
key: K,
14+
value: T
15+
) {
16+
const array = object[key];
17+
if (array) {
18+
array.push(value);
19+
} else {
20+
object[key] = [value];
21+
}
22+
}
23+
24+
// e.g.
25+
const foo: {x?: number[]; y?: string[]; } = {};
26+
appendToOptionalArray(foo, 'x', 123); // ok
27+
appendToOptionalArray(foo, 'y', 'bar'); // ok
28+
appendToOptionalArray(foo, 'y', 12); // should fail
29+
appendToOptionalArray(foo, 'x', "no"); // should fail
30+
31+
//// [paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.js]
32+
"use strict";
33+
exports.__esModule = true;
34+
function appendToOptionalArray(object, key, value) {
35+
var array = object[key];
36+
if (array) {
37+
array.push(value);
38+
}
39+
else {
40+
object[key] = [value];
41+
}
42+
}
43+
exports.appendToOptionalArray = appendToOptionalArray;
44+
// e.g.
45+
var foo = {};
46+
appendToOptionalArray(foo, 'x', 123); // ok
47+
appendToOptionalArray(foo, 'y', 'bar'); // ok
48+
appendToOptionalArray(foo, 'y', 12); // should fail
49+
appendToOptionalArray(foo, 'x', "no"); // should fail
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
=== tests/cases/compiler/paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts ===
2+
// Using a homomorphic mapped type over `T`
3+
// Produces a lower-priority inference for `T` than other
4+
// positions, allowing one to override the priority the argument
5+
// order would usually imply
6+
type Lower<T> = { [K in keyof T]: T[K] };
7+
>Lower : Symbol(Lower, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 0, 0))
8+
>T : Symbol(T, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 11))
9+
>K : Symbol(K, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 19))
10+
>T : Symbol(T, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 11))
11+
>T : Symbol(T, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 11))
12+
>K : Symbol(K, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 19))
13+
14+
export function appendToOptionalArray<
15+
>appendToOptionalArray : Symbol(appendToOptionalArray, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 41))
16+
17+
K extends string | number | symbol,
18+
>K : Symbol(K, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 6, 38))
19+
20+
T
21+
>T : Symbol(T, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 7, 37))
22+
23+
>(
24+
object: { [x in K]?: Lower<T>[] },
25+
>object : Symbol(object, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 9, 2))
26+
>x : Symbol(x, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 10, 13))
27+
>K : Symbol(K, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 6, 38))
28+
>Lower : Symbol(Lower, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 0, 0))
29+
>T : Symbol(T, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 7, 37))
30+
31+
key: K,
32+
>key : Symbol(key, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 10, 36))
33+
>K : Symbol(K, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 6, 38))
34+
35+
value: T
36+
>value : Symbol(value, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 11, 9))
37+
>T : Symbol(T, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 7, 37))
38+
39+
) {
40+
const array = object[key];
41+
>array : Symbol(array, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 14, 7))
42+
>object : Symbol(object, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 9, 2))
43+
>key : Symbol(key, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 10, 36))
44+
45+
if (array) {
46+
>array : Symbol(array, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 14, 7))
47+
48+
array.push(value);
49+
>array.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
50+
>array : Symbol(array, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 14, 7))
51+
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
52+
>value : Symbol(value, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 11, 9))
53+
54+
} else {
55+
object[key] = [value];
56+
>object : Symbol(object, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 9, 2))
57+
>key : Symbol(key, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 10, 36))
58+
>value : Symbol(value, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 11, 9))
59+
}
60+
}
61+
62+
// e.g.
63+
const foo: {x?: number[]; y?: string[]; } = {};
64+
>foo : Symbol(foo, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 23, 5))
65+
>x : Symbol(x, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 23, 12))
66+
>y : Symbol(y, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 23, 25))
67+
68+
appendToOptionalArray(foo, 'x', 123); // ok
69+
>appendToOptionalArray : Symbol(appendToOptionalArray, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 41))
70+
>foo : Symbol(foo, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 23, 5))
71+
72+
appendToOptionalArray(foo, 'y', 'bar'); // ok
73+
>appendToOptionalArray : Symbol(appendToOptionalArray, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 41))
74+
>foo : Symbol(foo, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 23, 5))
75+
76+
appendToOptionalArray(foo, 'y', 12); // should fail
77+
>appendToOptionalArray : Symbol(appendToOptionalArray, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 41))
78+
>foo : Symbol(foo, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 23, 5))
79+
80+
appendToOptionalArray(foo, 'x', "no"); // should fail
81+
>appendToOptionalArray : Symbol(appendToOptionalArray, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 4, 41))
82+
>foo : Symbol(foo, Decl(paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts, 23, 5))
83+
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
=== tests/cases/compiler/paramsOnlyHaveLiteralTypesWhenAppropriatelyContextualized.ts ===
2+
// Using a homomorphic mapped type over `T`
3+
// Produces a lower-priority inference for `T` than other
4+
// positions, allowing one to override the priority the argument
5+
// order would usually imply
6+
type Lower<T> = { [K in keyof T]: T[K] };
7+
>Lower : Lower<T>
8+
9+
export function appendToOptionalArray<
10+
>appendToOptionalArray : <K extends string | number | symbol, T>(object: { [x in K]?: Lower<T>[] | undefined; }, key: K, value: T) => void
11+
12+
K extends string | number | symbol,
13+
T
14+
>(
15+
object: { [x in K]?: Lower<T>[] },
16+
>object : { [x in K]?: Lower<T>[] | undefined; }
17+
18+
key: K,
19+
>key : K
20+
21+
value: T
22+
>value : T
23+
24+
) {
25+
const array = object[key];
26+
>array : { [x in K]?: Lower<T>[] | undefined; }[K]
27+
>object[key] : { [x in K]?: Lower<T>[] | undefined; }[K]
28+
>object : { [x in K]?: Lower<T>[] | undefined; }
29+
>key : K
30+
31+
if (array) {
32+
>array : { [x in K]?: Lower<T>[] | undefined; }[K]
33+
34+
array.push(value);
35+
>array.push(value) : number
36+
>array.push : (...items: Lower<T>[]) => number
37+
>array : Lower<T>[]
38+
>push : (...items: Lower<T>[]) => number
39+
>value : T
40+
41+
} else {
42+
object[key] = [value];
43+
>object[key] = [value] : T[]
44+
>object[key] : { [x in K]?: Lower<T>[] | undefined; }[K]
45+
>object : { [x in K]?: Lower<T>[] | undefined; }
46+
>key : K
47+
>[value] : T[]
48+
>value : T
49+
}
50+
}
51+
52+
// e.g.
53+
const foo: {x?: number[]; y?: string[]; } = {};
54+
>foo : { x?: number[] | undefined; y?: string[] | undefined; }
55+
>x : number[] | undefined
56+
>y : string[] | undefined
57+
>{} : {}
58+
59+
appendToOptionalArray(foo, 'x', 123); // ok
60+
>appendToOptionalArray(foo, 'x', 123) : void
61+
>appendToOptionalArray : <K extends string | number | symbol, T>(object: { [x in K]?: Lower<T>[] | undefined; }, key: K, value: T) => void
62+
>foo : { x?: number[] | undefined; y?: string[] | undefined; }
63+
>'x' : "x"
64+
>123 : 123
65+
66+
appendToOptionalArray(foo, 'y', 'bar'); // ok
67+
>appendToOptionalArray(foo, 'y', 'bar') : void
68+
>appendToOptionalArray : <K extends string | number | symbol, T>(object: { [x in K]?: Lower<T>[] | undefined; }, key: K, value: T) => void
69+
>foo : { x?: number[] | undefined; y?: string[] | undefined; }
70+
>'y' : "y"
71+
>'bar' : "bar"
72+
73+
appendToOptionalArray(foo, 'y', 12); // should fail
74+
>appendToOptionalArray(foo, 'y', 12) : any
75+
>appendToOptionalArray : <K extends string | number | symbol, T>(object: { [x in K]?: Lower<T>[] | undefined; }, key: K, value: T) => void
76+
>foo : { x?: number[] | undefined; y?: string[] | undefined; }
77+
>'y' : "y"
78+
>12 : 12
79+
80+
appendToOptionalArray(foo, 'x', "no"); // should fail
81+
>appendToOptionalArray(foo, 'x', "no") : any
82+
>appendToOptionalArray : <K extends string | number | symbol, T>(object: { [x in K]?: Lower<T>[] | undefined; }, key: K, value: T) => void
83+
>foo : { x?: number[] | undefined; y?: string[] | undefined; }
84+
>'x' : "x"
85+
>"no" : "no"
86+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// @strict: true
2+
// Using a homomorphic mapped type over `T`
3+
// Produces a lower-priority inference for `T` than other
4+
// positions, allowing one to override the priority the argument
5+
// order would usually imply
6+
type Lower<T> = { [K in keyof T]: T[K] };
7+
8+
export function appendToOptionalArray<
9+
K extends string | number | symbol,
10+
T
11+
>(
12+
object: { [x in K]?: Lower<T>[] },
13+
key: K,
14+
value: T
15+
) {
16+
const array = object[key];
17+
if (array) {
18+
array.push(value);
19+
} else {
20+
object[key] = [value];
21+
}
22+
}
23+
24+
// e.g.
25+
const foo: {x?: number[]; y?: string[]; } = {};
26+
appendToOptionalArray(foo, 'x', 123); // ok
27+
appendToOptionalArray(foo, 'y', 'bar'); // ok
28+
appendToOptionalArray(foo, 'y', 12); // should fail
29+
appendToOptionalArray(foo, 'x', "no"); // should fail

0 commit comments

Comments
 (0)