TypeScript C++-style const modifier on class members

vwkv1x7d  于 2个月前  发布在  TypeScript
关注(0)|答案(4)|浏览(39)

🔍 搜索词

const method parameter keyword readonly class
C++类似的const方法
带有const关键字的类方法
"as const"用于类类型

✅ 可实现性检查清单

⭐ 建议

我肯定以前在哪里看到过这个建议,但找不到它 #35313
允许在类对象上使用 as const 通过将方法标记为 const (语法待定)。
一个const方法(就像C++)不允许修改 this 的属性或调用任何未标记为 const 的方法。
被标记为 as const 的对象也同样是只读的,只有标记为 const 的方法可以调用。

📃 动机示例

跟踪可变和不可变之间的差异可能会很棘手,当你不熟悉你正在使用的库(或者如果它的编写得很糟糕)。在许多库( react 状态, vue 引用(浅层vs深层), preact/signals )中,修改值可能是也可能不是必需的。
有时调试可变性错误也会很痛苦。

const start = new Point(0, 0);
const line: Point[] = [];

for (let i = 0; i < 10; i++) {
  line.push(start.add(i * 10, Math.random()));
}

// equivalent to
const line = new Array(10).fill(new Point(450, Math.random()));

第一种声明语法使用 const 装饰

class Point {
	constructor(public x: number, public y: number) { }
	const clone(): Point { ... }

	add(other: PointLike): this { ... }
}

const p = new Point(0, 0) as const; // type is { readonly x: number, readonly y: number, readonly clone(): Point } (`add` has been removed)

第二种声明语法使用 this: const 参数

class Point {
	constructor(public x: number, public y: number) { }
	clone(this: const): Point { ... }

	add(other: PointLike): this { ... }
}

const p = new Point(0, 0) as const; // type is { readonly x: number, readonly y: number, readonly clone(): Point } (`add` has been removed)

我个人更喜欢第一种语法,其中 const 是装饰。

参数语法1

function noModifyPoint(p: const Point) {
	p.clone().add(1, 1);
}

function modifyPoint(p: Point) {
	p.add(1, 1);
}

const p = new Point(0, 0) as const;

noModifyPoint(p); // ok
modifyPoint(p); // Argument of type `const Point` is not assignable to parameter of type `Point`. Type `const Point` is missing the following properties from type `Point`: add

不要与

function foo() {
	const p = arguments[0];
	//...
}

(顺便说一下,对于那个,更合适的语法应该是 foo(const p: Point)foo(const p: const Point),但那会导致OOS)混淆。

参数语法2

function noModifyPoint(p: Readonly<Point>) {
	p.clone().add(1, 1);
}

function modifyPoint(p: Point) {
	p.add(1, 1);
}

const p = new Point(0, 0) as const;

noModifyPoint(p); // ok
modifyPoint(p); // Argument of type `Readonly<Point>` is not assignable to parameter of type `Point`. Type `Readonly<Point>` is missing the following properties from type `Point`: add

再次,我喜欢语法1。const类型推断需要在编译器中进行,这使得看起来像一个实用程序类型会令人困惑。使用 const 也反映了第一种声明语法。
推断出的新只读类型应该足够简单,将任何读写属性转换为只读,并删除未标记为const的所有函数。
为了简单起见,箭头方法属性应该像处理其他属性一样处理。

class Point {
	constructor(public x: number, public y: number) { }
	clone(this: const): Point { ... }

	unsafelyModifyThis: () => { this.x = 10; }
}

const p = new Point(0, 0) as const;

p.unsafelyModifyThis(); // OK

我之所以建议这个是因为需要在某处划出一条界线,表明这个特性变得有多复杂。正如TypeScripts第三个非目标所提到的,这是在有用性和简单性之间的权衡。
它已经可以打破类型系统了,而程序员有责任不要做愚蠢的事情。

其他类型

const a1 = [1, 2, 3] as const;
const a2 = [1, 2, 3] as Readonly<[number, number, number]>;

function aFunc1<T>(p: const Array<T>) {
	// syntactically valid but is probably useful since Array doesn't have any built-in const decorations
	// the resulting type would be `{ readonly [index: number]: T; readonly length: number }`
	// also not sure how it would work with the `ReadonlyArray<T>` built-in type
	...
}

function prim(n: const number) { ... } //error

💻 用例

  1. 你打算用这个做什么?
    这对于表示非原始数据结构的数据的类(即结构体)最有用。
  2. 目前存在的缺点是什么?
    补丁不是DRY的,需要手动定义所有类型的const变体。
  3. 在等待期间你正在使用什么解决方法?
    手动定义一个 ReadonlyPoint 变化并将其转换为它。
djp7away

djp7away1#

我们正在考虑在旗帜下关闭{ readonly x: number } -> { x: number }的完整性漏洞,在这一点上,您将能够仅用现有的操作来表达这一点,例如:

class Point
  readonly x: number;
  readonly y: number;
  modify(this: Mutable<Point>, x: number, y: number) {

  }
}
zz2j4svz

zz2j4svz3#

这是你打算的吗?
我最近在想,我确实更喜欢Rust的默认为const的风格,但用这种语法,我不确定创建可变对象的正确方法。

j8yoct9x

j8yoct9x4#

我刚刚意识到我没有明确指定这一点,但理想情况下,“const”标志将适用于任何函数的任何参数。

$x_1a^0b^1x$

相关问题