在TypeScript中将属性修饰器限制为特定的已配置类型

问题描述 投票:0回答:1

注意:这个问题扩展了Property decorator only for a specific property type

--

我的目标是设计一个简单的ORM,其中模型可以这样定义:

@model.model()
class User extends model.Model {

  @model.attr(model.StringType)
  user: string;

  @model.attr(model.StringType)
  age: number;

}

在这个模型中,我希望编译器抛出一个类型错误,因为StringType不能应用于number类型的属性。但是我不能让它正常工作 - 不会抛出任何错误。

我的代码到目前为止:

interface Constructor<T> {
  new (...args: any[]): T;
}

abstract class BaseType<T> {}

class StringType extends BaseType<string> {}

type RecordKey = string | symbol;

export function attr<T>(type: Constructor<BaseType<T>>) {
  return <K extends RecordKey, C extends Record<K, T>>(ctor: C, key: K) => {
    console.log(ctor, key);
  }
}

关于这段代码如何工作的一些指示在这里非常有用。

typescript
1个回答
1
投票

打字稿是结构上键入的,这是整个答案的关键。在这种情况下,它意味着任何普通对象都可以是BaseType<T>,因为它没有字段/方法。请注意,推断类型在操场上的{}中为T报告@model.attr(model.StringType)

以下任务完全没问题(number可以是任何东西):

abstract class BaseType<T> { }
const t: BaseType<number> = { };

要求指定泛型,请尝试:

function attr<T = never>(type: Constructor<BaseType<T>>) { ... }
// ...
  @model.attr<string>(model.StringType)
  user: string

但请注意,它将允许@model.attr<number>(model.StringType),因为再次,任何对象是BaseType<number>

如果你的BaseType接口尚未完成,请继续填写它,你可能会发现有足够的打字稿来锁定和推断。例如(完全随意,但你得到了想法,可以测试推理):

abstract class BaseType<T> {
  deserialize: (s: string) => T;
}
© www.soinside.com 2019 - 2024. All rights reserved.