🔍 搜索词
const method parameter keyword readonly class
C++类似的const方法
带有const关键字的类方法
"as const"用于类类型
✅ 可实现性检查清单
- 这不会对现有的TypeScript/JavaScript代码造成破坏性的改变
- 这不会改变现有JavaScript代码的运行时行为
- 这可以在不根据表达式的类型发射不同的JS的情况下实现
- 这不是一个运行时特性(例如库功能、JavaScript输出的非ECMAScript语法、新的JS语法糖等)
- 这不是一个请求添加新实用类型的请求: https://github.com/microsoft/TypeScript/wiki/No-New-Utility-Types
- 这个特性将与我们设计目标的其他部分一致: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ 建议
我肯定以前在哪里看到过这个建议,但找不到它 #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
💻 用例
- 你打算用这个做什么?
这对于表示非原始数据结构的数据的类(即结构体)最有用。 - 目前存在的缺点是什么?
补丁不是DRY的,需要手动定义所有类型的const变体。 - 在等待期间你正在使用什么解决方法?
手动定义一个ReadonlyPoint
变化并将其转换为它。
4条答案
按热度按时间djp7away1#
我们正在考虑在旗帜下关闭
{ readonly x: number }
->{ x: number }
的完整性漏洞,在这一点上,您将能够仅用现有的操作来表达这一点,例如:pb3skfrl2#
相关: #35313
zz2j4svz3#
这是你打算的吗?
我最近在想,我确实更喜欢Rust的默认为const的风格,但用这种语法,我不确定创建可变对象的正确方法。
j8yoct9x4#
我刚刚意识到我没有明确指定这一点,但理想情况下,“const”标志将适用于任何函数的任何参数。
$x_1a^0b^1x$