js/ts在Rust或扩展Swift中有类似的东西吗?



js/ts是否有类似于Rust中的impl或Swift中的扩展?这是为具有特定形状的对象实现方法的良好实践。我们可以把userSetAge(user, x => x + 1)替换成user.setAge(x => x + 1)。不仅如此,在复制对象被复制后,它仍然可以工作。

下面是一个React数据获取和渲染的例子:
interface User {
name: string;
age: number;
setAge(fn: (age: number) => number): User;
}
impl User {
setAge(self, fn) {
self.age = fn(self.age);
return this;
}
}
// it works
const eczn: User = { name: 'eczn', age: 17 };
({ ...eczn }).setAge(x => x + 1);
import useSWR, { mutate } from 'swr';
// React App
function UserCard(props: { user: User }) {
return (
<div onClick={() => {
mutate(
`/api/user/${props.user.name}`,
props.user.setAge(x => x + 1)
);
}}>
Current Age: { props.user.age }
</div>
)
}
function App() {
const { data, loading } = useSWR<User>('/api/user/eczn')
if (loading) return <div>loading ...</div>
return <UserCard user={{ ...data }} />
}

一个错误的实现::Object.prototype.setAge

Object.prototype.setAge = function(fn) {
this.age = fn(this.age);
}
const eczn: User = { name: 'eczn', age: 17 };
({ ...eczn }).setAge(x => x + 1);

显然,这是一个不好的做法。

如果你使用Javascript/Typescript类,那么你可以通过在子类上声明它们来覆盖基类的方法。JS解释器在对象中查找您调用的任何方法,如果没有找到,它就查找原型。使用extends关键字声明子类。详见https://javascript.info/class-inheritance

在上面的例子中,您使用User的接口而不是类。接口在Typescript中只是一个用于类型检查的编译时构造,所以你不能在它上面实现任何东西,而且Typescript在运行时已经消失了,所以它不能帮助你。

如果你把User变成一个类,那么你当然可以在它上面定义setAge方法,然后从它派生,然后在它上面调用setAge。甚至可以使用展开运算符,只要不调用原型上的方法(不复制),就保留函数

简而言之,没有等同于Rust的impl,这是因为JS是面向对象的,而Rust不是。Rust基于组合而不是继承的思想。所以在JS中,你必须使用面向对象的方法。

最新更新