question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add undefined to tuple index signature, or reject keys that are not "keyof tuple"

See original GitHub issue

Search Terms

Tuple index signature

Suggestion

I am opening up this issue as Seperate from https://github.com/microsoft/TypeScript/issues/13778 since I am ok with the current interpretation of the Array.

declare var strArray: string[] // infinitely long list of type string
var a : strArray[10 as number]  // ok; a is string

but this fails in conjunction with tuples

declare var strTuple: [number, number] // length = 2
var a : strTuple[10 as number]  // absolutely not ok; a is string; 

Better Options:

var a : strTuple[10 as number] should either be string | undefined or it should give a type error similar to:

var a = { 0:  10, 1: 20} as const;
a[10 as number]; // type 'number' can't be used to index type

Tuples are already aware of boundaries and properly return undefined for more specific number types:

const t0: [string][0] = 'hello' // ok
const t1: [string][1] = 'hello' // Type '"hello"' is not assignable to type 'undefined'.

// therefore this is already true!
const t2: [string][0|1] // string | undefined 

why would type number act any differently?

Use Cases

// Easy fix for for loops

for (let i = 0 as 0 | 1; i < 2; i++) { 
  var definitly_string = strTuple[i] // type string
  var j = i + someNumber;
  var not_definitly_string  = strTuple[j] //lets you know you need to be careful
}

You could use keyof typeof strTuple instead of 0 | 1 when you fix this https://github.com/microsoft/TypeScript/issues/27995

for (let i = 0 as keyof typeof strTuple; i < strTuple.length; i++) { 
  var definitly_string = strTuple[i] // type string
  var j = i + someNumber;
  var not_definitly_string = strTuple[j] //lets you know you need to be careful
} 

Given that strictNullChecks still allow typed arrays to do this:

var notString1 = strArray[Infinity]; // no error, not undefined
var notString2 = strArray[NaN]; // no error, not undefined

It would be nice to have a mechanism that could allow you to declare arrays with better type safety.

Examples

Checklist

My suggestion meets these guidelines:

  • This wouldn’t be a breaking change in existing TypeScript/JavaScript code
  • This wouldn’t change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn’t a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript’s Design Goals.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:1
  • Comments:5

github_iconTop GitHub Comments

2reactions
lonewarrior556commented, Jul 10, 2020

All I am saying is this

const t0: [string][0] = 'hello' // ok
const t1: [string][1] = 'hello' // Type '"hello"' is not assignable to type 'undefined'.

// therefore this is already true
const t2: [string][0|1] // string | undefined 

// How can you justify this behavior?
const t3: [string][number] // string 

Yes, for of/ forEach loops are better (although they still don’t protect you from spares arrays) But there are uses for using array indices

this was what brought me to the other thread:

var notString1 = aa[Infinity]; // no error, not undefined
var notString2 = aa[NaN]; // no error, not undefined

Which originally caused my runtime error as a number became a NaN, then returned an undefined from a tuple… All of which was type safe

So objectively this is a problem that does happen.

1reaction
lonewarrior556commented, Jul 9, 2020

@thw0rted good points

If I understand your issue correctly, you want [T,U,V][number] to type as T | U | V | undefined instead of just T | U | V. Is that right?

     yes, either that or throw // type 'number' can't be used to index type)


I don’t see how that’s any different from / better than #13778.

     tuples were release much later and much more limited in use… so unlike #13778 this would not be the single most breaking change in any project I've ever followed. meaning this is releasable.


This wouldn’t be a breaking change in existing TypeScript/JavaScript code

This is not true.

     you are right, but it would be a minor breaking change, And honestly because the tuple [string] can accept [0 as const] but not [1 as const] means it cannot accept number so this is closer to a bug fix than feature


declare const two: [string, string];
const oneOfthem = two[Math.floor(Math.random()*2)];
oneOfThem.charAt(0);

     Unfortuanly TS does not know Math.floor(1 as const) is 1      you expect it to?


Before your proposed change, oneOfThem types as string, but after it would type as string | undefined. All the arguments that have been made against #13778 would then apply – “but I checked that the index stays in-bounds!”, etc.

 // quick fix?
 const oneOfthem = two[Math.floor(Math.random()*2) as 1 | 2 ];

// general case
 const oneOfthem = two[Math.floor(Math.random() * two.length) as keyof two ];
Read more comments on GitHub >

github_iconTop Results From Across the Web

Typescript: Remove entries from tuple type - Stack Overflow
PrependToTuple is util that takes item A and list T and add it on first place when A is not undefined. PrependToTuple<undefined, []>...
Read more >
Documentation - Object Types - TypeScript
Index Signatures ​​ This index signature states that when a StringArray is indexed with a number , it will return a string ....
Read more >
Mastering TypeScript mapped types - LogRocket Blog
In this post, we'll cover mapped types in TypeScript, a real-world example of them, and utility types including Partial, Readonly, and Pick.
Read more >
An overview of computing with types • Tackling TypeScript
It lists the property keys of an object type. We give the output of keyof the ... The result is a tuple type...
Read more >
Advanced Types - TypeScript
This allows you to add together existing types to get a single type that has ... If you have a type with a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found