Is there a way to convert a string type literal (not runtime value) to its corresponding number type literal, e.g. '1'
to 1
?
I want to narrow a variable to being a key of an object (note the programmer asserts the type of obj
is exact, as TS doesnt yet have support for it):
const isKeyOfExactTable = <O extends object, T extends string | number>(o: O, key: T): key is ??? => Object.hasOwnProperty.call(o, key);
// what to put here? -------------------------------------------------------------------------^^^
There has always been the issue of JS object properties only being strings, but every member access implicitly converting numbers. As such, TS properties can actually be numbers, and even if not, the problem would then appear at the member access, just one step earlier.
Since TS 4.1, template literal types solve one direction, which makes this almost fully possible (if either side has number literals, one can just convert, and check), if the properties have a number
index, can just take all numbers from the key. Sadly, if the key is number
, and the object has strings as properties, which represent numbers, there simply seems to be no way. One can even check, that there really is a problem:
type HasStringNumber<T> = T extends `${number}`
? 'houston, we have a problem'
: 'all systems green';
type Test<O extends object, K extends string | number> = number extends K
? HasStringNumber<keyof O>
: 'all systems green';
But no way to identify the actual number, e.g. this just more or less expectedly infers the input string:
type WhatNumber<T extends string> = T extends `${infer N}` ? N : 'Not a number';`
To give a straight in-/output example for the problem:
declare const o: { '1': 0 };
declare const k: number;
if (isKeyOfExactTable(o, k)) { /* typeof k is 1 */ }