TypeScript 允许设置器返回

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

搜索词

设置器不能返回值
装饰器

建议

默认情况下,JavaScript不对设置器的返回值做任何处理,但这并不是错误。
允许设置器作为默认行为并添加标志以打开错误。

使用场景

  • 覆盖设置器并使用原始设置器返回值的装饰器。
  • 直接调用设置器函数并期望返回值的方法。

示例

一个实时示例是来自ember-decorators的@computed,它与ember的旧行为相匹配。
使用遗留装饰器的代码示例(也可以使用阶段2装饰器):

function saved (target: {}, key: string | symbol, descriptor: PropertyDescriptor) {
  const savedStore = new WeakMap();

  const oldSet = descriptor.set;
  if (!oldSet) {
    throw new Error('Must be used on setter only');
  }
  const oldGet = descriptor.get;
  return {
    ...descriptor,
    get () {
      let response = savedStore.get(this);
      if (!response && oldGet) {
        response = oldGet.call(this);
      }
      return response;
    },
    set (value: any) {
      const result = oldSet.call(this, value);
      savedStore.set(this, result);
    }
  };
}

class Foo {
  @saved
  get square () {
    // default value of 1 if none is saved
    return 1;
  }
  set square (value: number) {
    return value * value;
  }
}

检查清单

我的建议满足以下指导原则:

  • 这不会对现有的TypeScript / JavaScript代码造成破坏性更改
  • 这不会改变现有JavaScript代码的运行时行为
  • 这可以在不根据表达式的类型发出不同的JS的情况下实现
  • 这不是一个运行时特性(例如新的表达式级语法)
cclgggtu

cclgggtu1#

在对这个问题进行进一步思考后,我认为可能有一个更好的解决方案。

与其仅仅允许set返回,如果有任何装饰器,那么setter和getter的预期类型可以由装饰器确定,并且在没有访问器装饰器存在时应该具有当前行为的默认值。

如果这是一个更可取的建议,我可以相应地更新标题和描述,或者是否应该创建一个新的问题并将其关闭?

由于装饰器尚未达到第三阶段,是否已经设置了一个跟踪机制(标签?)来区分在新实现开始工作时的提议?

hof1towb

hof1towb2#

我希望看到允许属性装饰器返回 PropertyDescriptor<T>,并反过来被装饰的属性将是类型为 T 的。
目前我的装饰器代码返回一个属性描述符,但我不得不表达属性的类型。
例如:

class {
@mydecorator(arg)
myprop: string
}

如果 mydecorator 返回 PropertyDescriptor<string>,我希望 TSC 能够推断出 myprop 的类型为 string

u1ehiz5o

u1ehiz5o3#

我将为这个投一票。在用作“setter”的函数中的一个return语句在规范中不是错误,并且在大多数浏览器中只是默默地被忽略。
另一个用例:

class A {
  @AutoImplemented
  set name(value: string) {
    if (value === this.name) return;
    this.name = value;
    console.log('set name to: ' + value);
    return true; // Use return value to indicate that if the assignment action is performed.
  }
}

我制作了一个“AutoImplemented”装饰器,它将为属性创建一个带有_前缀的后备字段,添加getter函数,并自动替换对它的赋值。只接受脏值。
它还将在原型中生成$getName$setName助手,以允许覆盖访问器,这仍然是针对ES5的问题。( 338 , 4465 )

class B extends A {
  @AutoImplemented
  set name(value: string) {
    // super.name = value; <-- this will not work.
    if (!super.$setName(value)) return;
    this.updateWhenValueIsDirty();
    return true;
  }
}

updateWhenValueIsDirty应该仅在值实际更改时调用,但super.name = value语句无法告诉我赋值是否执行(甚至在ES5中也无法编译)。将setter方法作为示例方法调用并检查其返回值是使此工作的方法。

xzlaal3s

xzlaal3s4#

嗯,我们需要一个标志来阻止或绕过这种错误!
在一个良好的设计模式中,我们可能希望使用返回来打破条件流程。
举个例子:

set value(v: string) {
		if (this._deriveTargetValue) return (this._deriveTargetValue = v); 
		this._value = v;
	}

而不是

set value(v: string) {
		if (this._deriveTargetValue){
			this._deriveTargetValue = v
		} else {
			this._value = v;
		}
	}

很多人不喜欢 elseif design ,所以使用 batch if return 也是有效的中断方式!
谢谢
为了在概念上更抽象,这是一个很好的setter设计:

set foo(v: string) {
		if (this._disableLocalFoo) return; 
		if (this._derivedFoo) return this.deriveFoo(v); 
		this._foo= v;
	}

相关问题