Search code examples
typescripttype-narrowing

Typescript: allow typeof check narrowing when comparing against a const


I want the following:

const a: unknown = 'this is a string';
const stringType = 'string';
if (typeof a === stringType){
    console.log(a.toLocaleUpperCase())
}

But it gives me an error: 'a' is of type 'unknown' I know it works if I just compare typeof a against 'string' but I want to compare it against a const variable. How do I achieve this? Is there some tsconfig.json option?

P.S. The reason for this is to optimise my code. This code is supposed to run thousands of times per single user request, so I'd rather compare it against an already defined variable than a newly created string every time


Solution

  • This is not possible. Narrowing in TypeScript only happens in very specific circumstances, which were explicitly implemented for that purpose, to handle idiomatic coding patterns. The compiler doesn't spend resources trying to figure out if something you've written is logically equivalent to one of the supported patterns, as such analysis scales quite poorly.

    The typeof type gaurd only supports code like if (typeof a === "string") {⋯}. It does not support if ((typeof a) === "string") {⋯} or if (typeof a === ("string")) {⋯}, see microsoft/TypeScript#8574. And it doesn't support saving typeof a or "string" to another variable and checking the variables, see microsoft/TypeScript#49583. Nor does it support comparing typeof a to typeof b, see microsoft/TypeScript#21406. Such issues, when raised, are generally either closed as design limitations, or left open as feature requests awaiting feedback from the community to see if it's there's enough demand for it. So far there really hasn't been. These patterns are just not anywhere near as common as the supported patterns.

    If you really want to see it supported you could always open your own feature request (or comment on microsoft/TypeScript#49583 which is quite close), but it is really unlikely to happen. Especially because it lacks a compelling use case here; there isn't any indication that the idiomatic if (typeof a === "string") {⋯} performs worse at runtime than the unusual if (typeof a === stringType) {⋯}. I would expect that "string" would end up being interned by any reasonable JavaScript engine, although whether or not that's true is out of scope for the question as asked. That seems to be more appropriate for Do common JavaScript implementations use string interning?. Unless you can show that runtime performance really is improved by saving "string" in a variable, it wouldn't make for a convincing reason to add narrowing support for it to TypeScript.