如何解决TypeScript - 作为类型保护的属性装饰器
我想知道是否可以在 TypeScript 中使用 属性装饰器 作为 类型保护 以确保属性是不空|未定义。
假设有以下示例。
class MyClass {
@isrequired()
public myProperty: string | undefined;
}
请注意,由于严格的编译器设置 (strictnullchecks),必须编写 string | undefined
。因此,仅使用 string
作为类型是不可能的。我知道可以像这样使用非空断言:public myProperty!: string
。但这实际上是装饰者应该注意的。
最后,装饰器基本上会检查属性是否在特定时间点设置,如果没有则抛出错误。这个检查显然不是在构建时完成的,否则就不需要这种方法了。它在不久之后执行 - 例如在 Angular 等框架的 lifcylce 钩子 中。我知道 构造函数 本身中的类型检查是不正确的。不过这个我可以接受。如果检查成功,则属性的类型应缩小到 string
,因此您可以安全地使用它,例如this.property.split(" ")
。
我想知道这样的事情在理论上是否可行?提前致谢。
解决方法
不,这在 TypeScript 中目前是不可能的;装饰器不会改变他们装饰的东西的类型。长期以来一直建议在 microsoft/TypeScript#4881 中允许这样做,但该问题对于此类功能的确切工作方式存在重大分歧。
更重要的是,在 decorators proposal 达到 the TC39 process 的第 3 阶段以介绍 JavaScript 之前,不太可能对 TypeScript 中装饰器的工作方式进行任何更改。一般而言,TypeScript 只会在潜在的 JavaScript 功能成为相对稳定的候选者时才尝试支持它们。装饰器是 earlier features of TypeScript 之一,但过早采用功能有缺点;在某些时候,装饰器可能会以与 TypeScript 最初预期的方式截然不同的形式将其放入 JavaScript,然后 TypeScript 将不得不进行重大更改。现在您必须启用 --experimentalDecorators
compiler option 才能使用它们。看起来装饰器已经在第 2 阶段停滞了很长时间(至少……三年、四年?)。所以就目前而言,我不希望有任何变化。
如果您需要此功能,您可以做什么?好吧,你总是可以回到非装饰器的世界,而是使用一个函数来修改传递给它们的类构造函数。例如(不确定这是否是一个好的实现):
function isRequired<
C extends new (...args: any[]) => any,K extends keyof InstanceType<C>
>(
ctor: C,prop: K
) {
return class extends ctor {
constructor(...args: any[]) {
super(...args);
}
init() {
if (this[prop as keyof this] == null) throw new Error(prop + " is nullish!!");
}
} as Pick<C,keyof C> & (new (...args: ConstructorParameters<C>) =>
({ [P in keyof InstanceType<C>]:
P extends K ? NonNullable<InstanceType<C>[P]> : InstanceType<C>[P]
} & { init(): void })
);
}
如果您在类构造函数和属性名称上调用 isRequired()
,生成的构造函数将在该属性处创建具有不可为空值的实例,至少在您对该实例调用 init()
之后(如一些生命周期钩子的例子):
const MyClass = isRequired(class MyClass {
public myProperty: string | undefined;
},"myProperty");
type MyClass = InstanceType<typeof MyClass>;
const myClass = new MyClass();
myClass.myProperty = "okay";
myClass.init();
console.log(myClass.myProperty.toUpperCase()); // OKAY
const badMyClass = new MyClass();
badMyClass.init(); // myProperty is nullish!!
console.log(badMyClass.myProperty.toUpperCase()); // NEVER GET HERE
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。