2

I have the following JavaScript code in a test file:

for (let [input, expected] of [
  ['<h1>test</h1>', ['</h1>']],
  ['<h1><b>test</b></h1>', ['</h1>', '</b>']],
  ['<h1><b>test</b> lol</h1>', ['</h1>']],
]) {
  const result = functionToTest(input);
  for (let i in expected) {
    if (result[i] !== expected[i]) {
      throw Error("test failed")
    }
  }
}

TypeScript does not accept this code because functionToTest expects a string and TypeScript thinks that input has type string | string[].

One thing that works is to put my test data in a separate variable and declare its type as a list of tuples:

const testData: [string, string[]][] = [
  ['<h1>test</h1>', ['</h1>']],
  ['<h1><b>test</b></h1>', ['</h1>', '</b>']],
  ['<h1><b>test</b> lol</h1>', ['</h1>']],
]

for (let [input, expected] of testData) {
  const result = listClosingTagsAtEnd(input);
  for (let i in expected) {
    if (result[i] !== expected[i]) {
      throw Error("test failed")
    }
  }
}

However I would like not to have to create a variable to store data that I only need once. I liked it better when it was declared in the for loop.

I tried to do type declaration in the for loop with let [input, expected]: [string, string[]] of but I get the error The left-hand side of a 'for...of' statement cannot use a type annotation..

I also tried to add : [string, string[]] after the declaration of the test data in the for loop but then TypeScript thinks I am using a JavaScript label.

How can I have properly typed destructuration while keeping the declaration of test data inside the for loop?

1 Answer 1

5

I figured this out myself by chance, just “trying random things”, so I wanted to post it to Stack Overflow in case other people have the same problem. Here is how you do it:

for (let [input, expected] of <[string, string[]][]>[
  //                          ^--------------------^
  //                             type declaration
  ['<h1>test</h1>', ['</h1>']],
  ['<h1><b>test</b></h1>', ['</h1>', '</b>']],
  ['<h1><b>test</b> lol</h1>', ['</h1>']],
]) {
  const result = functionToTest(input);
  for (let i in expected) {
    if (result[i] !== expected[i]) {
      throw Error("test failed")
    }
  }
}

Edit: Wow, found another solution on this stack overflow answer! Just add as const after the literal:

for (let [input, expected] of [
  ['<h1>test</h1>', ['</h1>']],
  ['<h1><b>test</b></h1>', ['</h1>', '</b>']],
  ['<h1><b>test</b> lol</h1>', ['</h1>']],
] as const) {
//   ^---^
//    HERE
  const result = functionToTest(input);
  for (let i in expected) {
    if (result[i] !== expected[i]) {
      throw Error("test failed")
    }
  }
}

In this case, TypeScript considers that input has type "<h1>test</h1>" | "<h1><b>test</b></h1>" | "<h1><b>test</b> lol</h1>" for instance, which is ... the most exact description of input's type indeed.

Sign up to request clarification or add additional context in comments.

1 Comment

adding "as const" at the end, as suggested in your edit, fixed the problem for me. This is the best way that I found to fix Tupple's destructuring

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.