Javascript 模仿TypeScript中的扩展方法
这是一个有趣的挑战。我正在用类似于C#的用法在TypeScript github to中阅读这一旧版本。有两种主要的方法被提出,一种是添加语法糖来扩展经常不受欢迎的对象原型,另一种是重写调用站点(参见优缺点) 我在想,也许我们可以用另一种方式,模仿同样适用于JavaScript的扩展方法 假设我们有以下功能:Javascript 模仿TypeScript中的扩展方法,javascript,typescript,extension-methods,Javascript,Typescript,Extension Methods,这是一个有趣的挑战。我正在用类似于C#的用法在TypeScript github to中阅读这一旧版本。有两种主要的方法被提出,一种是添加语法糖来扩展经常不受欢迎的对象原型,另一种是重写调用站点(参见优缺点) 我在想,也许我们可以用另一种方式,模仿同样适用于JavaScript的扩展方法 假设我们有以下功能: 函数includesAnyOf(数组:T[],…搜索元素:T[]){ 返回searchElements.some(=>array.includes()); } //例如: 常数a=[1,2
函数includesAnyOf(数组:T[],…搜索元素:T[]){
返回searchElements.some(=>array.includes());
}
//例如:
常数a=[1,2,3];
常数b=3;
包括(a,b);//真的
//作为扩展方法,它看起来像:
//a.包括(b)项;
现在我想实现函数ext
,这样我可以:
ext(a).includesAnyOf(b)
保留参数的所有类型。我不知道这是否可能,但我从这开始,不知道如何完成它
功能扩展(对象:任何){
返回{
includesAnyOf:(…args:any[])=>includesAnyOf(…??)
};
}
我认为这是一个有趣的挑战,你认为这是如何实现的,以及如何推广它,或者你能想出一个更好的方法吗?我发现最简单的方法就是使用它来完成任务
function ext<T, E>(obj: T, extension: E) {
return (receiver: (extended: T & E) => any) => {
receiver(new Proxy(obj, {
get(target, prop, receiver) {
if(prop in extension)
return extension[prop];
return Reflect.get(...arguments);
},
// TODO has, set, etc. according to needs
} as T & E));
};
}
ext(a, { includesAnyOf })(a => {
a.includesAnyOf("stuff");
});
函数includesAnyOf(数组:T[],…搜索元素:T[]){
返回searchElements.some(=>array.includes());
}
从“lodash”导入{partial};
常数a=[1,2,3];
常数b=3;
常数ext=(o)=>{
返回{
includesAnyOf:部分(includesAnyOf,o)
};
};
console.log(
ext(a).includesAnyOf(b)//真
);
我发现的最简单的方法是使用来执行
函数includesAnyOf(数组:T[],…搜索元素:T[]){
返回searchElements.some(=>array.includes());
}
从“lodash”导入{partial};
常数a=[1,2,3];
常数b=3;
常数ext=(o)=>{
返回{
includesAnyOf:部分(includesAnyOf,o)
};
};
console.log(
ext(a).includesAnyOf(b)//真
);
感谢您接受挑战!我的目标是有一个更可读的代码,但前提是它不破坏强键入和自动完成。你的答案似乎不起作用。对于a.includesAnyOf(“2”)
它返回false
@orad字符串不是强类型的数字,你在内部a
上得到了自动完成,但是你必须键入ext(a,{……方法})(a=>)
才能得到扩展,依我看那没有用你是对的,我错了,但它不能为我编译,我只能在浏览器中运行它。是的,语法仍然冗长,我同意它没有那么有用。感谢您接受挑战!我的目标是有一个更可读的代码,但前提是它不破坏强键入和自动完成。你的答案似乎不起作用。对于a.includesAnyOf(“2”)
它返回false
@orad字符串不是强类型的数字,你在内部a
上得到了自动完成,但是你必须键入ext(a,{……方法})(a=>)
才能得到扩展,依我看那没有用你是对的,我错了,但它不能为我编译,我只能在浏览器中运行它。是的,语法仍然冗长,我同意它没有那么有用。你可能会对管道操作符感兴趣-尽管它还处于非常早期的阶段。哇,这太强大了!谢谢分享!我不知道为什么您希望ext(a)
成为函数而不是扩展对象。也就是说,为什么你想做ext(a)(x=>x.includesAnyOf(1))
而不是仅仅做(ext(a))。includesAnyOf(1)
?顺便说一句,我认为一个令人困惑的问题是,你想要的是比TS舒适地处理的更高的顺序类型,即使是它可以处理的。如果includesAnyOf
专门处理具体类型number[]
,您可能会使用通用扩展函数获得良好的强类型。但由于您可能希望它支持泛型T
的T[]
,这是更高的阶数,您可能会看到未知[]
或其他过早解析的泛型。@jcalz回答您的第一个问题,我可能想得太多了!我基本上是在寻找最接近a.includesAnyOf(b)
语法的路径,而无需扩展对象原型或克隆数组。因此,如果我们能做ext(a)。includesAnyOf(b)
,那就更好了。你可能会对管道操作符感兴趣,尽管它还处于非常早期的阶段。哇,这太强大了!谢谢分享!我不知道为什么您希望ext(a)
成为函数而不是扩展对象。也就是说,为什么你想做ext(a)(x=>x.includesAnyOf(1))
而不是仅仅做(ext(a))。includesAnyOf(1)
?顺便说一句,我认为一个令人困惑的问题是,你想要的是比TS舒适地处理的更高的顺序类型,即使是它可以处理的。如果includesAnyOf
专门处理具体类型number[]
,您可能会使用通用扩展函数获得良好的强类型。但由于您可能希望它支持泛型T
的T[]
,这是更高的阶数,您可能会看到未知[]
或其他过早解析的泛型。@jcalz回答您的第一个问题,我可能想得太多了!我基本上是在寻找最接近a.includesAnyOf(b)
语法的路径,而无需扩展对象原型或克隆数组。因此,如果我们能做ext(a)。includesAnyOf(b)
,那就更好了。
function ext<T, E>(obj: T, extension: E) {
return (receiver: (extended: T & E) => any) => {
receiver(new Proxy(obj, {
get(target, prop, receiver) {
if(prop in extension)
return extension[prop];
return Reflect.get(...arguments);
},
// TODO has, set, etc. according to needs
} as T & E));
};
}
ext(a, { includesAnyOf })(a => {
a.includesAnyOf("stuff");
});