41

If I do not want the value of a parameter change within a function scope, is there any way to annotate that with Typescript?

I've tried:

function walk(const fileName: string): string[] {
// -----------^
}

But it does not work.

4
  • 1
    I don't believe this is currently possible. Commented Jul 13, 2017 at 16:15
  • At least there is an option to make arrays readonly: function foo(bar: readonly number[]) { }. This feature is not limited to function declarations, and it converts a mutable array to immutable array. Commented Jul 5, 2019 at 15:09
  • wwo caveats about that though: 1. It still lets you reassign bar = ... (it only prevents bar[i] = ... or bar.pop(), etc.). 2. readonly is shallow so if you have an array of objects instead of simple numbers, it won't prevent bar[i].whatever = .... Unfortunately immutability is an area where TypeScript is still missing a lot of useful stuff! Commented Aug 19, 2021 at 1:25
  • If this became possible everyone would start annotating every single argument as const by default to be "safe", like we do with variables, and that could get annoying. Commented Nov 14, 2022 at 9:26

5 Answers 5

20

This can be achieved with the const type parameter constraint from TypeScript version 5.0.

function walk<const T extends string>(fileName: T): string {
  // TS is upset here because we're attempting to modify a constant
  fileName = 'my new value';

  // TS knows you're returning a string here
  return fileName;
}

See: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#const-type-parameters

Note: You can technically do fileName = fileName; and TS will compile - this is slightly different behavior than a const variable declaration which is treated as readonly.

Sign up to request clarification or add additional context in comments.

1 Comment

You are my hero
9

There is no way to do it right now, and it may not be, as it is not possible in ES6 either:

How to make function parameter constant in JavaScript?

This workaround doesn't work for TypeScript anyway.

4 Comments

Got it. Unfortunately, I do not see how the JavaScript workaround can work with Typescript. First, if parameters are not defined, TS complains with error TS2554: Expected 0 arguments, but got 1,. Second, the tuple syntax results in error TS2461: Type 'IArguments' is not an array type.
@kiewic It doesn't work for TS. I pointed out that is not possible, and using the workaround for TypeScript violates function's argument contract.
My bad, I missed that part of your answer. Thanks for helping.
@kiewic You didn't. It was edited after you comment, as I saw it may not be clear enough.
5

A short workaround with a few extra characters gets close:

function fo(args: {x: number,y: string}): void{
    const {x,y} = args;
    x = 2; // Cannot assign to 'x' because it is a constant.ts(2588)
}
function fa(...args: [x: number,y: string]): void{
    const [x,y] = args;
    x = 2; // Cannot assign to 'x' because it is a constant.ts(2588)
}

but you can still overwrite using args.x=2.

1 Comment

Best answer IMO, most practical, accurately solves the problem with minimal fuzz, and the pattern of passing a single object as parameter is already a good practice for other reasons.
4

Typescript doesn't support const in the function parameter yet, but you can do readonly parameters.

Typescript 3.4 added support for readonly arrays and tuples (not objects yet).

Examples:

function foo(arr: readonly string[]) {}

or

function foo(pair: readonly [string, string]) {}

or

function foo(arr: ReadonlyArray<string>) {}

1 Comment

Are you sure, it seems Readonly<T> works with objects too: typescriptlang.org/docs/handbook/utility-types.html#readonlyt
4

It's not supported yet, but you can upvote this feature request & follow it for any updates in the future: https://github.com/microsoft/TypeScript/issues/18497

In the meantime your best bet is to use a linter rule to make arguments const by default, like ESLint's no-param-reassign rule. In any rare cases where you need an argument to be not const, you can either use eslint-disable-line each place you reassign it, or wrap the whole function in an eslint-disable / eslint-enable pair to make all its arguments non-const.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.