DEV Community 👩‍💻👨‍💻

Discussion on: The Record Utility Type in TypeScript

 
peerreynders profile image
peerreynders • Edited on

just because it handles the numbers as strings, is that really a concern though?

On the surface no, because TypeScript tries to enforce consistent access with the declared type.

But it still leaves a JavaScript type coercion footgun in place:

const record: Record<string | number, string> = {
  0: 'zero',
  1: 'one',
  2: 'two',
};

const oldOne = 1;
const newOne = '1';

console.assert(record[oldOne] === 'one');
record[newOne] = 'newOne';
// Oops
console.assert(record[oldOne] === 'newOne');

// Meanwhile TS flags this as an error
// "This condition will always return 'false' since the types 'number' and 'string' have no overlap"
// Actually it returns `true` due to type coercion; TS just doesn't like it...
// console.assert(oldOne == newOne);

// ...because
console.assert(typeof oldOne !== typeof newOne);

// At least this works (ES2022)
console.assert(Object.hasOwn(record, 2));
console.assert(Object.hasOwn(record, (2).toString()));
Enter fullscreen mode Exit fullscreen mode

Similarly

const values = ['zero', 'one', 'two'];

const oldOne = 1;
const newOne = '1';
const anotherOne = '01';

console.assert(values[oldOne] === 'one');

values[newOne] = 'newOne';
console.assert(values[oldOne] === 'newOne');

console.assert(typeof oldOne !== typeof newOne);

console.assert(Object.hasOwn(values, oldOne));
console.assert(Object.hasOwn(values, oldOne.toString()));
console.assert(Object.hasOwn(values, newOne));
console.assert(!Object.hasOwn(values, anotherOne));
Enter fullscreen mode Exit fullscreen mode

So TypeScript being typed had an opportunity to clean things up at least for objects to restrict property keys to strings and symbols but existing JavaScript code bases sometimes use numbers as property keys (for convenience) and not supporting that could have hurt adoption.