Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between TypeScript const assertions and declarations?

I just read about the new const assertion feature in TypeScript 3.4 RC and I'm not seeing how it does anything differently from using const declarations.

I tested this out using an example from the announcement page that apparently demonstrates how using as const (const assertion) prevents literal types from being widened (e.g., "circle" to string).

// Example from official announcement
function getShapes() {
  let result = [
    { kind: "circle", radius: 100 },
    { kind: "square", sideLength: 50 },
  ] as const;

  return result;
}

for (const shape of getShapes()) {
  if (shape.kind === "circle") {
    console.log("Circle radius", shape.radius);
  } else {
    console.log("Square side length", shape.sideLength);
  }
}

// Output:
// Circle radius 100
// Square side length 50

However, when I removed the const assertion and used a const declaration instead, nothing changed in the compiler output or console output and no errors were thrown.

// Altered getShapes function
function getShapes() {
  const result = [
    { kind: "circle", radius: 100 },
    { kind: "square", sideLength: 50 },
  ];

  return result;
}

So what's the difference? The announcement page lists three reasons to use const assertions:

• no literal types in that expression should be widened (e.g. no going from "hello" to string)
• object literals get readonly properties
• array literals become readonly tuples

but it doesn't explain how assertions and declarations are different.

like image 353
Adam Avatar asked Nov 30 '25 04:11

Adam


2 Answers

This example uses console.log to test inferred types. console.log does not care much about its argument type, so there are no errors in both cases.

The result is different if the test requires more specific type:

// Altered getShapes function
function getShapes() {
  const result = [
    { kind: "circle", radius: 100 },
    { kind: "square", sideLength: 50 },
  ];

  return result;
}

for (const shape of getShapes()) {
  if (shape.kind === "circle") {
    const radius: number = shape.radius;
  } else {
    const length: number = shape.sideLength;
  }
}

With --strictNullChecks on, you will get two errors:

t.ts:25:11 - error TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.

25     const radius: number = shape.radius;
             ~~~~~~

t.ts:29:11 - error TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.

29     const length: number = shape.sideLength;
             ~~~~~~

As advertised for this feature, there are no errors when as const assertion is used to make the compiler to infer precise type.

For reference, here's the type inferred for return type of getShapes() with const declaration:

 ( { kind: string; radius: number; sideLength?: undefined; } 
  |{ kind: string; sideLength: number; radius?: undefined; } ) []

As you can see, kind is widened to string, and array element type is a union with elements that have all properties declared, only some of them are optional in some union members - that's why you get no errors in console log when you are logging for example shape.radius - console.log will happily log undefined if the union member is of the wrong type.

Here's the type inferred for return type of getShapes() with as const assertion:

readonly [
   { readonly kind: "circle"; readonly radius: 100; }, 
   { readonly kind: "square"; readonly sideLength: 50; }
]

Now it's readonly tuple type, not an array, and it has precise types for each tuple member (and kind is proper literal type, as expected).

like image 166
artem Avatar answered Dec 03 '25 11:12

artem


A const declaration is a variable declaration that can't be changed after declaration. This is a Javascript feature that Typescript supports.

const x ={ n: 10} ;
x.n = 11; //ok
x= { n:11}; // error 

const assertion is a type assertion that has the impact you described on the assertion target.

const x ={ n: 10} as const;
x. n = 11; // error n is readonly 
like image 27
Titian Cernicova-Dragomir Avatar answered Dec 03 '25 09:12

Titian Cernicova-Dragomir



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!