Skip to content

Commit 99ea99b

Browse files
authored
Properly check singleton labeled tuple before unwrapping (#48554)
* properly check if singleton labeled tuple has optional element * also check if labeled element is rest
1 parent aa3c5a7 commit 99ea99b

File tree

5 files changed

+118
-1
lines changed

5 files changed

+118
-1
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15860,7 +15860,11 @@ namespace ts {
1586015860
}
1586115861

1586215862
function isSingletonTupleType(node: TypeNode) {
15863-
return isTupleTypeNode(node) && length(node.elements) === 1 && !isOptionalTypeNode(node.elements[0]) && !isRestTypeNode(node.elements[0]);
15863+
return isTupleTypeNode(node) &&
15864+
length(node.elements) === 1 &&
15865+
!isOptionalTypeNode(node.elements[0]) &&
15866+
!isRestTypeNode(node.elements[0]) &&
15867+
!(isNamedTupleMember(node.elements[0]) && (node.elements[0].questionToken || node.elements[0].dotDotDotToken));
1586415868
}
1586515869

1586615870
/**
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//// [singletonLabeledTuple.ts]
2+
type AliasOptional = [p?: number]
3+
4+
// literal type vs type alias
5+
type Literal = [p?: number] extends [unknown] ? true : false // Expect `Literal` to be `false`
6+
type Alias = AliasOptional extends [unknown] ? true : false // Expect `Alias` to be `false`
7+
8+
// labeled tuple vs normal tuple
9+
type Labeled = [p?: number] extends [unknown] ? true : false // Expect `Labeled` to be `false`
10+
type Normal = [number?] extends [unknown] ? true : false // Expect `Normal` to be `false`
11+
12+
13+
type AliasRest = [...p: number[]];
14+
15+
type LiteralRest = [...p: number[]] extends [unknown] ? true : false; // Expect `LiteralRest` to be `false`
16+
type AliasedRest = AliasRest extends [unknown] ? true : false; // Expect `AliasedRest` to be `false`
17+
type NormalRest = [...number[]] extends [unknown] ? true : false; // Expect `NormalRest` to be `false`
18+
19+
//// [singletonLabeledTuple.js]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/singletonLabeledTuple.ts ===
2+
type AliasOptional = [p?: number]
3+
>AliasOptional : Symbol(AliasOptional, Decl(singletonLabeledTuple.ts, 0, 0))
4+
5+
// literal type vs type alias
6+
type Literal = [p?: number] extends [unknown] ? true : false // Expect `Literal` to be `false`
7+
>Literal : Symbol(Literal, Decl(singletonLabeledTuple.ts, 0, 33))
8+
9+
type Alias = AliasOptional extends [unknown] ? true : false // Expect `Alias` to be `false`
10+
>Alias : Symbol(Alias, Decl(singletonLabeledTuple.ts, 3, 60))
11+
>AliasOptional : Symbol(AliasOptional, Decl(singletonLabeledTuple.ts, 0, 0))
12+
13+
// labeled tuple vs normal tuple
14+
type Labeled = [p?: number] extends [unknown] ? true : false // Expect `Labeled` to be `false`
15+
>Labeled : Symbol(Labeled, Decl(singletonLabeledTuple.ts, 4, 59))
16+
17+
type Normal = [number?] extends [unknown] ? true : false // Expect `Normal` to be `false`
18+
>Normal : Symbol(Normal, Decl(singletonLabeledTuple.ts, 7, 60))
19+
20+
21+
type AliasRest = [...p: number[]];
22+
>AliasRest : Symbol(AliasRest, Decl(singletonLabeledTuple.ts, 8, 56))
23+
24+
type LiteralRest = [...p: number[]] extends [unknown] ? true : false; // Expect `LiteralRest` to be `false`
25+
>LiteralRest : Symbol(LiteralRest, Decl(singletonLabeledTuple.ts, 11, 34))
26+
27+
type AliasedRest = AliasRest extends [unknown] ? true : false; // Expect `AliasedRest` to be `false`
28+
>AliasedRest : Symbol(AliasedRest, Decl(singletonLabeledTuple.ts, 13, 69))
29+
>AliasRest : Symbol(AliasRest, Decl(singletonLabeledTuple.ts, 8, 56))
30+
31+
type NormalRest = [...number[]] extends [unknown] ? true : false; // Expect `NormalRest` to be `false`
32+
>NormalRest : Symbol(NormalRest, Decl(singletonLabeledTuple.ts, 14, 62))
33+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/singletonLabeledTuple.ts ===
2+
type AliasOptional = [p?: number]
3+
>AliasOptional : AliasOptional
4+
5+
// literal type vs type alias
6+
type Literal = [p?: number] extends [unknown] ? true : false // Expect `Literal` to be `false`
7+
>Literal : false
8+
>true : true
9+
>false : false
10+
11+
type Alias = AliasOptional extends [unknown] ? true : false // Expect `Alias` to be `false`
12+
>Alias : false
13+
>true : true
14+
>false : false
15+
16+
// labeled tuple vs normal tuple
17+
type Labeled = [p?: number] extends [unknown] ? true : false // Expect `Labeled` to be `false`
18+
>Labeled : false
19+
>true : true
20+
>false : false
21+
22+
type Normal = [number?] extends [unknown] ? true : false // Expect `Normal` to be `false`
23+
>Normal : false
24+
>true : true
25+
>false : false
26+
27+
28+
type AliasRest = [...p: number[]];
29+
>AliasRest : AliasRest
30+
31+
type LiteralRest = [...p: number[]] extends [unknown] ? true : false; // Expect `LiteralRest` to be `false`
32+
>LiteralRest : false
33+
>true : true
34+
>false : false
35+
36+
type AliasedRest = AliasRest extends [unknown] ? true : false; // Expect `AliasedRest` to be `false`
37+
>AliasedRest : false
38+
>true : true
39+
>false : false
40+
41+
type NormalRest = [...number[]] extends [unknown] ? true : false; // Expect `NormalRest` to be `false`
42+
>NormalRest : false
43+
>true : true
44+
>false : false
45+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
type AliasOptional = [p?: number]
2+
3+
// literal type vs type alias
4+
type Literal = [p?: number] extends [unknown] ? true : false // Expect `Literal` to be `false`
5+
type Alias = AliasOptional extends [unknown] ? true : false // Expect `Alias` to be `false`
6+
7+
// labeled tuple vs normal tuple
8+
type Labeled = [p?: number] extends [unknown] ? true : false // Expect `Labeled` to be `false`
9+
type Normal = [number?] extends [unknown] ? true : false // Expect `Normal` to be `false`
10+
11+
12+
type AliasRest = [...p: number[]];
13+
14+
type LiteralRest = [...p: number[]] extends [unknown] ? true : false; // Expect `LiteralRest` to be `false`
15+
type AliasedRest = AliasRest extends [unknown] ? true : false; // Expect `AliasedRest` to be `false`
16+
type NormalRest = [...number[]] extends [unknown] ? true : false; // Expect `NormalRest` to be `false`

0 commit comments

Comments
 (0)