0

To define a function type, below example does not allow const

interface Square{
    readonly color: string;
    readonly area: number;
}

interface compareTo{
    (const v1: Square, const v2: Square): number;  // syntax error      
}

How to compare v1 & v2 without changing the pointer of an object(Square) it is pointing to?

overexchange
  • 15,768
  • 30
  • 152
  • 347
  • 4
    How is this 'const' supposed to work? Why should function argument be const? It doesn't matter whether it's `const` or not inside function. – Estus Flask May 02 '18 at 16:42
  • 4
    Possible duplicate of [Can a typescript parameter be annotated as const?](https://stackoverflow.com/questions/45086031/can-a-typescript-parameter-be-annotated-as-const) – Michał Perłakowski May 02 '18 at 16:48
  • @estus Interface implementation should make sure that `v1` and `v2` objects are only read but not written. [here](https://github.com/shamhub/Computing/blob/master/code_Sedgewick/design2Code/list/list.hpp#L31) is a scenario – overexchange May 02 '18 at 17:03
  • 1
    It's unclear what 'read' and 'written' is about in your case. `const` doesn't prevent objects from being modified, as the answer explains. Please, provide an example that shows what you're trying to achieve/avoid. – Estus Flask May 02 '18 at 17:07
  • @estus Query edited – overexchange May 02 '18 at 17:18

2 Answers2

3

There's no way to declare this because it would have no effect on anything. const in TypeScript doesn't mean immutable -- it applies only to a binding, and a function parameter is not an externally-visible binding.

Ryan Cavanaugh
  • 209,514
  • 56
  • 272
  • 235
1

As another answer explains, const doesn't prevent objects from being modified in ES6, it only prevents reassignments.

In order to prevent parameter reassignments globally, TSLint no-parameter-reassignment rule can be used.

In order to prevent object modifications at runtime, Object.freeze should be used. This can be enforced at compilation time with Readonly mapped type. However, this won't have any effect if the types are compatible:

interface compareTo {
    (v1: Readonly<Square>, v2: Readonly<Square>): number;      
}
const foo: compareTo = (a: Square, b: Square) => {
  a.area = 0;
  return 1;
}   

Generally, this isn't the responsibility of an interface to tell how function should internally work, it just describes its interface, so it would be:

interface compareTo {
    (v1: Square, v2: Square): number;      
}
const foo: compareTo = (a: Readonly<Square>, b: Readonly<Square>) => {
  a.area = 0; // error
  return 1;
}   

But this will work if types are inferred from generic type, i.e. a type isn't specified in compareTo implementation:

interface compareTo<T = Readonly<Square>> {
    (v1: T, v2: T): number;      
}

const foo: compareTo = (a, b) => {
  a.area = 0; // error
  return 1;
}   
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • interface should be able to tell whether `v1` can be modified. We do this in Java, C. Anyways, `let foo:compareTo = (a: Readonly, b: Readonly) => {a = {color: 'red', area: 20}; return 1;}` allows modification – overexchange May 02 '18 at 17:52
  • As I mentioned, an interface only describes function inputs and outputs, not how function works. It's possible to do that with Readonly but not necessarily necessary. JS semantics differs from the C++ example you've linked because objects are passed by reference everywhere in JS, and you can't restrict a developer from shooting into the foot everywhere. Common JS methods like array `map`, `filter`, `sort` aren't typed to prevent object modifications, even though it's rarely a good idea there. – Estus Flask May 02 '18 at 18:02
  • I do not get all three example in this answer, because `interface Square{readonly color: string; readonly area: number;}` would suffice for not allowing `a.area=0`. I did not get the value-add of using `Readonly` – overexchange May 02 '18 at 18:11
  • I was under impression that you wanted to omit `readonly` fields in Square and enforce them in `compareTo` only. If you didn't, it still remains unclear what purpose `const` is supposed to serve in your case. – Estus Flask May 02 '18 at 18:23
  • I would not like to allow something like this... `a = {color: 'white', area: 20};` in the function. `const` helps in such scenario for variables unlike parameters. – overexchange May 02 '18 at 18:38
  • There's no way to prevent this in JS or TS. You can reassign a parameter anywhere. That's a matter of style and personal preference. I don't see a reason to enforce this for a particular function. You can enforce this globally with https://palantir.github.io/tslint/rules/no-parameter-reassignment/ as a part of your coding style. I updated the answer. – Estus Flask May 02 '18 at 18:56