Home > Blockchain >  Narrowing a type to a constant for Typescript in a .js file?
Narrowing a type to a constant for Typescript in a .js file?

Time:10-17

I have some .js config files and a tsconfig for these files with checkJs: true. A library (Terser) has the type:

ecma: 5 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020

In my config file, I have ecma: 2017. TS considers its type to be ecma: number. In a .ts file, I can just use as const. In a .js file, is there any way to get TS to narrow 2017 to a constant?

CodePudding user response:

You can use a const assertion in jsdoc, as detailed in this issue

// let config: {
//     readonly ecma: "2017";
// }
let config = /** @type {const} */ ({ 
  ecma: "2017"
})

// Or 
// let config2: {
//     ecma: "2017";
// }
let config2 = { 
  ecma: /** @type {const} */ ("2017")
}

Playground Link

Note: the () around the expression you want to make const is required.

CodePudding user response:

I would do two things in a combination to ensure it is a constant:

First - make sure that the props is not changeable runtime nomatter what.

///config.js
const config = {
  anotherProp: true,
  ecma: 2017
};
Object.defineProperty(config, "ecma", { value: 2017, writable: false });
export default config;

Second create d.ts file to "tests" the typescirpt this prop is readonly

/// config.d.ts
type Config = {
  anotherProp: string;
  readonly ecma: 2017;
};

declare const conf: Config;

export default conf;

The result will be that the typescript will complain about changes

//ts error: Cannot assign to 'ecma' because it is a read-only property.ts(2540)
config.ecma = 6;

And even If you try to hack it - it will fail runtime:

//runtime error: Cannot assign to read only property 'ecma' of object '#<Object>'
(config as any).ecma = 6;

Playground link here: here

  • Related