Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unbounded type is not strict #40235

Closed
royling opened this issue Aug 25, 2020 · 4 comments · Fixed by #40254
Closed

unbounded type is not strict #40235

royling opened this issue Aug 25, 2020 · 4 comments · Fixed by #40254
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@royling
Copy link

royling commented Aug 25, 2020

TypeScript Version: 4.0.2

Search Terms: unbounded

Code

type Strings = [string, string];
type Numbers = number[];

type Unbounded = [...Strings, ...Numbers, boolean];
//   ^?

const data: Unbounded = ['a', 'b', false, false]; // <-- No error?
console.log(data);

Expected behavior:
The above Unbounded type should allow only the last element in the tuple as boolean, other elements in range [2, -2] if available should be numbers only.

Actual behavior:
[...number[], boolean] is now handled as <number | boolean>[]

Playground Link:
https://www.typescriptlang.org/play?#code/C4TwDgpgBAysBOBLAdgcwM5QLxQNroRVQBooCk0BdAbgChRIoA5AVwFsAjCeTHZdrvFw1a9cNACqyDgHsWyACYQF2PADoNcChlIa1rTt3SlZMgDYQAhshEB6W1EcA9APyiAxjOQEoCy8EsALigpWXklFRxcAHJLaNJojnioADNLM3QIUjSMiBFPb3MINTMZVAAKPwCASmogA

Related Issues:
No.

@RyanCavanaugh
Copy link
Member

Tuple types don't support this operation, but we should be issuing the same error at the declaration site as we would if there wasn't a type alias used here

Shorter

type Numbers = number[];
type Unbounded = [...Numbers, boolean];
const data: Unbounded = [false, false];

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Aug 25, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.1.0 milestone Aug 25, 2020
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Aug 25, 2020
@royling
Copy link
Author

royling commented Aug 27, 2020

Tuple types don't support this operation

@RyanCavanaugh This seems opposite of the update in 4.0 doc:

The second change is that rest elements can occur anywhere in a tuple - not just at the end!

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 27, 2020

Previously, rest elements could only occur at the end. Now, they can occur anywhere, as long as they meet the criteria of either being bounded-length tuples themselves, or being type parameters.

@royling
Copy link
Author

royling commented Aug 28, 2020

Thanks for the reply.

as long as they meet the criteria of either being bounded-length tuples themselves, or being type parameters.

Should this be mentioned in the doc? Or, the Unbounded example used in Variadic Tuple Type looks inappropriate, IMHO.

@RyanCavanaugh RyanCavanaugh added Rescheduled This issue was previously scheduled to an earlier milestone and removed Rescheduled This issue was previously scheduled to an earlier milestone labels Aug 31, 2020
craigphicks added a commit to craigphicks/TypeScript-cph that referenced this issue May 13, 2022
 Changes to be committed:
	modified:   FIX_tuple-rest.md
	modified:   src/compiler/checker.ts
	new file:   tmp.cph.d/_aect.ts
	new file:   tmp.cph.d/_alect.ts
	renamed:    tests/cases/compiler/_cph1.ts -> tmp.cph.d/_cph1.ts
	renamed:    tests/cases/compiler/_vt2.ts -> tmp.cph.d/_vt2.ts

With entry condition for new code
```
    if (contextualType && isTupleType(contextualType)) {
```
Failing tests:
  80958 passing (5m)
  3 failing

  1)
         conformance tests
           conformance tests for tests/cases/conformance/types/tuple/variadicTuples2.ts
             Correct type/symbol baselines for tests/cases/conformance/types/tuple/variadicTuples2.ts:
     Error: New baseline created at tests/baselines/local/variadicTuples2.types
  2)
                conformance tests
           conformance tests for tests/cases/conformance/types/tuple/variadicTuples1.ts
             Correct errors for tests/cases/conformance/types/tuple/variadicTuples1.ts:
     Error: New baseline created at tests/baselines/local/variadicTuples1.errors.txt
  3)
         conformance tests
           conformance tests for tests/cases/conformance/types/tuple/variadicTuples1.ts
             Correct type/symbol baselines for tests/cases/conformance/types/tuple/variadicTuples1.ts:
     Error: New baseline created at tests/baselines/local/variadicTuples1.types

No difference in final result, only in intermediate types and error message.

```
$ diff -c6 tests/baselines/reference/variadicTuples1.types tests/baselines/local/variadicTuples1.types
*** tests/baselines/reference/variadicTuples1.types     2022-05-01 10:45:12.880934695 -0700
--- tests/baselines/local/variadicTuples1.types 2022-05-13 09:44:44.783651538 -0700
***************
*** 1394,1406 ****

  type Unbounded = [...Numbers, boolean];
  >Unbounded : [...number[], boolean]

  const data: Unbounded = [false, false];  // Error
  >data : [...number[], boolean]
! >[false, false] : [false, false]
  >false : false
  >false : false

  type U1 = [string, ...Numbers, boolean];
  >U1 : [string, ...number[], boolean]

--- 1394,1406 ----

  type Unbounded = [...Numbers, boolean];
  >Unbounded : [...number[], boolean]

  const data: Unbounded = [false, false];  // Error
  >data : [...number[], boolean]
! >[false, false] : [boolean, false]
  >false : false
  >false : false

  type U1 = [string, ...Numbers, boolean];
  >U1 : [string, ...number[], boolean]
```

```
$ diff -c6 tests/baselines/reference/variadicTuples2.types tests/baselines/local/variadicTuples2.types
*** tests/baselines/reference/variadicTuples2.types     2022-05-01 10:45:12.880934695 -0700
--- tests/baselines/local/variadicTuples2.types 2022-05-13 09:44:04.671647544 -0700
***************
*** 454,466 ****
  >1 : 1
  >'abc' : "abc"

  fn1([1, 'abc', true]);  // [string, boolean]
  >fn1([1, 'abc', true]) : [string, boolean]
  >fn1 : <T, U>(t: [...unknown[], T, U]) => [T, U]
! >[1, 'abc', true] : [number, string, boolean]
  >1 : 1
  >'abc' : "abc"
  >true : true

  declare function fn2<T, U>(t: [T, ...unknown[], U]): [T, U];
  >fn2 : <T, U>(t: [T, ...unknown[], U]) => [T, U]
--- 454,466 ----
  >1 : 1
  >'abc' : "abc"

  fn1([1, 'abc', true]);  // [string, boolean]
  >fn1([1, 'abc', true]) : [string, boolean]
  >fn1 : <T, U>(t: [...unknown[], T, U]) => [T, U]
! >[1, 'abc', true] : [number, string, true]
  >1 : 1
  >'abc' : "abc"
  >true : true

  declare function fn2<T, U>(t: [T, ...unknown[], U]): [T, U];
  >fn2 : <T, U>(t: [T, ...unknown[], U]) => [T, U]
***************
*** 484,496 ****
  >1 : 1
  >'abc' : "abc"

  fn2([1, 'abc', true]);  // [number, boolean]
  >fn2([1, 'abc', true]) : [number, boolean]
  >fn2 : <T, U>(t: [T, ...unknown[], U]) => [T, U]
! >[1, 'abc', true] : [number, string, boolean]
  >1 : 1
  >'abc' : "abc"
  >true : true

  // Repro from microsoft#39595
--- 484,496 ----
  >1 : 1
  >'abc' : "abc"

  fn2([1, 'abc', true]);  // [number, boolean]
  >fn2([1, 'abc', true]) : [number, boolean]
  >fn2 : <T, U>(t: [T, ...unknown[], U]) => [T, U]
! >[1, 'abc', true] : [number, string, true]
  >1 : 1
  >'abc' : "abc"
  >true : true

  // Repro from microsoft#39595
```

```
$ diff -c6 tests/baselines/reference/variadicTuples1.errors.txt tests/baselines/local/variadicTuples1.errors.txt
*** tests/baselines/reference/variadicTuples1.errors.txt        2022-05-01 10:45:12.880934695 -0700
--- tests/baselines/local/variadicTuples1.errors.txt    2022-05-13 09:44:42.575651323 -0700
***************
*** 33,45 ****
  tests/cases/conformance/types/tuple/variadicTuples1.ts(191,5): error TS2322: Type '[...T]' is not assignable to type '[...U]'.
    Type 'T' is not assignable to type 'U'.
      'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'readonly string[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Type 'string' is not assignable to type 'keyof [1, 2, ...T]'.
    Type '"2"' is not assignable to type '"0" | "1" | keyof T[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(357,26): error TS2322: Type 'string' is not assignable to type 'number'.
! tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Type '[false, false]' is not assignable to type '[...number[], boolean]'.
    Type at position 0 in source is not compatible with type at position 0 in target.
      Type 'boolean' is not assignable to type 'number'.

  ==== tests/cases/conformance/types/tuple/variadicTuples1.ts (20 errors) ====
      // Variadics in tuple types
--- 33,45 ----
  tests/cases/conformance/types/tuple/variadicTuples1.ts(191,5): error TS2322: Type '[...T]' is not assignable to type '[...U]'.
    Type 'T' is not assignable to type 'U'.
      'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'readonly string[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Type 'string' is not assignable to type 'keyof [1, 2, ...T]'.
    Type '"2"' is not assignable to type '"0" | "1" | keyof T[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(357,26): error TS2322: Type 'string' is not assignable to type 'number'.
! tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'.
    Type at position 0 in source is not compatible with type at position 0 in target.
      Type 'boolean' is not assignable to type 'number'.

  ==== tests/cases/conformance/types/tuple/variadicTuples1.ts (20 errors) ====
      // Variadics in tuple types
***************
*** 495,507 ****
      // Repro from microsoft#40235

      type Numbers = number[];
      type Unbounded = [...Numbers, boolean];
      const data: Unbounded = [false, false];  // Error
            ~~~~
! !!! error TS2322: Type '[false, false]' is not assignable to type '[...number[], boolean]'.
  !!! error TS2322:   Type at position 0 in source is not compatible with type at position 0 in target.
  !!! error TS2322:     Type 'boolean' is not assignable to type 'number'.

      type U1 = [string, ...Numbers, boolean];
      type U2 = [...[string, ...Numbers], boolean];
      type U3 = [...[string, number], boolean];
--- 495,507 ----
      // Repro from microsoft#40235

      type Numbers = number[];
      type Unbounded = [...Numbers, boolean];
      const data: Unbounded = [false, false];  // Error
            ~~~~
! !!! error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'.
  !!! error TS2322:   Type at position 0 in source is not compatible with type at position 0 in target.
  !!! error TS2322:     Type 'boolean' is not assignable to type 'number'.

      type U1 = [string, ...Numbers, boolean];
      type U2 = [...[string, ...Numbers], boolean];
      type U3 = [...[string, number], boolean];

```
craigphicks added a commit to craigphicks/TypeScript-cph that referenced this issue May 13, 2022
…to tuple-rest

```
$ diff -c6 tests/baselines/reference/variadicTuples1.errors.txt tests/baselines/local/variadicTuples1.errors.txt
*** tests/baselines/reference/variadicTuples1.errors.txt        2022-05-01 10:45:12.880934695 -0700
--- tests/baselines/local/variadicTuples1.errors.txt    2022-05-13 09:44:42.575651323 -0700
***************
*** 33,45 ****
  tests/cases/conformance/types/tuple/variadicTuples1.ts(191,5): error TS2322: Type '[...T]' is not assignable to type '[...U]'.
    Type 'T' is not assignable to type 'U'.
      'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'readonly string[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Type 'string' is not assignable to type 'keyof [1, 2, ...T]'.
    Type '"2"' is not assignable to type '"0" | "1" | keyof T[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(357,26): error TS2322: Type 'string' is not assignable to type 'number'.
! tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Type '[false, false]' is not assignable to type '[...number[], boolean]'.
    Type at position 0 in source is not compatible with type at position 0 in target.
      Type 'boolean' is not assignable to type 'number'.

  ==== tests/cases/conformance/types/tuple/variadicTuples1.ts (20 errors) ====
      // Variadics in tuple types
--- 33,45 ----
  tests/cases/conformance/types/tuple/variadicTuples1.ts(191,5): error TS2322: Type '[...T]' is not assignable to type '[...U]'.
    Type 'T' is not assignable to type 'U'.
      'T' is assignable to the constraint of type 'U', but 'U' could be instantiated with a different subtype of constraint 'readonly string[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(203,5): error TS2322: Type 'string' is not assignable to type 'keyof [1, 2, ...T]'.
    Type '"2"' is not assignable to type '"0" | "1" | keyof T[]'.
  tests/cases/conformance/types/tuple/variadicTuples1.ts(357,26): error TS2322: Type 'string' is not assignable to type 'number'.
! tests/cases/conformance/types/tuple/variadicTuples1.ts(397,7): error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'.
    Type at position 0 in source is not compatible with type at position 0 in target.
      Type 'boolean' is not assignable to type 'number'.

  ==== tests/cases/conformance/types/tuple/variadicTuples1.ts (20 errors) ====
      // Variadics in tuple types
***************
*** 495,507 ****
      // Repro from microsoft#40235

      type Numbers = number[];
      type Unbounded = [...Numbers, boolean];
      const data: Unbounded = [false, false];  // Error
            ~~~~
! !!! error TS2322: Type '[false, false]' is not assignable to type '[...number[], boolean]'.
  !!! error TS2322:   Type at position 0 in source is not compatible with type at position 0 in target.
  !!! error TS2322:     Type 'boolean' is not assignable to type 'number'.

      type U1 = [string, ...Numbers, boolean];
      type U2 = [...[string, ...Numbers], boolean];
      type U3 = [...[string, number], boolean];
--- 495,507 ----
      // Repro from microsoft#40235

      type Numbers = number[];
      type Unbounded = [...Numbers, boolean];
      const data: Unbounded = [false, false];  // Error
            ~~~~
! !!! error TS2322: Type '[boolean, false]' is not assignable to type '[...number[], boolean]'.
  !!! error TS2322:   Type at position 0 in source is not compatible with type at position 0 in target.
  !!! error TS2322:     Type 'boolean' is not assignable to type 'number'.

      type U1 = [string, ...Numbers, boolean];
      type U2 = [...[string, ...Numbers], boolean];
      type U3 = [...[string, number], boolean];

```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants