TypeScript Suggestion: readonly method

webghufk  于 4个月前  发布在  TypeScript
关注(0)|答案(9)|浏览(66)

问题:

当前,可以通过简单的赋值操作将一个方法(使用 ES6 method syntax 编写的函数)替换为另一个函数。例如,考虑以下代码片段:

class Person {
    constructor(...) {...}
    displayName (): string {...}
}
const x: Person = new Person(...)
x.displayName = function(this: Person): string {...} // Assignment

由于 readonly 修饰符不能用于方法,因此无法防止这种赋值操作。

建议:

方法始终是只读的。
以下代码完全相同:

class Person {
    displayName (): string {...}
}
class Person {
    readonly displayName: (this: Person) => string = function () {...}
}

兼容性:

这是一个破坏性更改。然而,方法语法是最近才出现的,并且主要在类中使用。将函数赋值给方法的代码肯定是很少见的。

临时解决方法:

不要在你的类和接口中使用方法语法。请注意,这会导致非常冗长的代码。
如果你使用接口,那么冗长是可以接受的。但是你也会遇到严格的协变性问题。

interface PersonI {
    readonly displayName: (this: Person) => string
}
rbl8hiat

rbl8hiat1#

相关讨论:#58296 (评论)

qaxu7uf2

qaxu7uf22#

我想要添加一个功能,即在方法事件中处理只读Map类型,如果不允许使用只读关键字。

class SomeClass {
    //public readonly SomeMethod() {} // 'readonly' modifier can only appear on a property declaration or index signature.
    public readonly SomeOtherMethod() {}
}
const someObject =  new SomeClass();
someObject.SomeOtherMethod = () => {}; // OK
const someOtherObject = new SomeClass() as Readonly<typeof SomeClass>
someOtherObject.SomeOtherMethod = () => {}; // Cannot assign to 'SomeOtherMethod ' because it is a constant or a read-only property.

一个严格伞形下的标志,默认将所有方法设置为只读,并强制使用属性函数来处理“可分配方法”,这也是受欢迎的。

nzrxty8p

nzrxty8p3#

@feeddageek It's allowed when you store method as arrow function class property:

class SomeClass {
    public readonly SomeOtherMethod = () => {};
}

const someObject =  new SomeClass();
someObject.SomeOtherMethod = () => { /* new impl */ }; //  error TS2540: Cannot assign to 'SomeOtherMethod' because it is a read-only property.
moiiocjp

moiiocjp4#

另一个解决方法(基于@feeddageek的想法)是强制使用一个返回对象“只读版本”的工厂:

class Person {
  /** Factory */
  static readonly from: (name: string) => Readonly<Person> = (name) => new Person(name)

  name: string

  protected constructor(name: string) {
    this.name = name
  }

  displayName(): string {
    return name
  }
}

const p = Person.from("Louise")
p.displayName = () => "Impersonation" // does not compile :)

注意,所有属性也都变为只读。
然而,如果TypeScript初学者阅读这段代码,他们可能会认为对象不能被改变(如果对象有可变方法,情况并非如此)。

5cg8jx4n

5cg8jx4n5#

@patrykuszynski 使用只读函数属性的问题在于它们不会在原型上编译,而是由构造函数构建到示例中。
此外,它们捕获了它们的 this ,而传统方法则没有。
(通过使用函数表达式而不是箭头函数来防止捕获 this 可以解决这个问题,但这不是重点)

更正:test2.inProto = test1.inProto; 实际上确实做了一些事情,但与手头的事情关系不大。

9rygscc1

9rygscc16#

这也是一个关于命名空间的问题。允许使用const/readonly会使代码更简洁,将其设为默认值可以防止库作者在实现被替换时感到惊讶。

$x_1^a_0b_1^x$

ulmd4ohb

ulmd4ohb7#

然而,这将破坏声明合并/模块增强,因为你不能在环境上下文中定义函数。

92vpleto

92vpleto8#

FYI, I filed #47003 which is basically the same request, and Ryan replied with a pointer to this issue and a comment that there hasn't been much interest so at this point action is unlikely. It occurred to me that the bar is probably lower to make a linter rule, which I think could be just as effective at catching accidental assignments as a language-level "readonly" modifier. I haven't asked yet but if I do I'll make sure to ping this issue.

wtzytmuj

wtzytmuj9#

我非常希望看到这种情况发生,因为当启用https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.md时,使用一个或多个方法作为函数参数的类会导致linter错误。
将类属性设置为不可变,但方法不能这样做,这也相当不一致。

相关问题