Search code examples
typescriptcoercion

`unknown` type is coerced to `string`, despite official semantics for `unknown`


I've read the official doc about the unknown type but I have some difficulties to really understand how it works.

One can read in the doc : "no operations are permitted on an unknown without first asserting or narrowing to a more specific type."

but if I have this function:

const foo = (x: unknown) => {
  return x + "3";
}

it's ok for TypeScript, but this function raises an error, telling that x is unknown:

const foo = (x: unknown) => {
  return x + 3;
}

why does it work with x + "3" ?

If casting is involved, true + 3 or {} + 3 works for instance, as well as true + "3".


Solution

  • This is because Typescript's designers have chosen to allow unchecked many of Javascript's implicit coercions, typically because they are so idiomatic.

    Suggestion: stricter operators #7989:

    Currently operators like "+" are defined such that they match their semantics in JS. The below are all allowed by the compiler and produce the shown values, even with --strictNullChecks on.

    • 2 + 'a' => "2a"
    • null + 'a' => "nulla" (!)
    • 2 - null => 2

    The Typescript maintainers have kept this issue open, suggesting that they are open to changing this, or at least adding a new compiler strictness flag.

    Project lead Ryan Cavanaugh says:

    Approved behavior change: under --strictNullChecks it should be an error to use a possibly-null/possibly-undefined operand in a +, -, /, *, |, &, ^, or ** expression. One exception is that string + nullable is still OK since that's very common for producing debugging strings.