javascript 受益于只有在示例化时才知道的文字类型

lokaqttq  于 2023-04-10  发布在  Java
关注(0)|答案(2)|浏览(89)

在TypeScript中,可以使用文字来设置参数的类型,例如:

type Allowed = "fizz" | "buzz";
 
class FizzBuzz {
  public identity(x: Allowed) {
    return x;
  }
}

这意味着下面的代码片段甚至在代码运行之前就会给予错误:

let fizzBuzz = new FizzBuzz()
fizzBuzz.identity("not-fizz-not-buzz");

然而,在我的场景中,当类被定义时,字面量是不知道的,但是当类被用来示例化一个对象时,它们是知道的。换句话说,它们被期望作为构造函数本身的参数。例如:

class FizzBuzz {
  constructor(allowed: string[]) {
    this.allowed = allowed;
  }

  public identity(x: this.allowed) {
    return x;
  }
}

let fizzBuzz = new FizzBuzz(["fizz", "buzz"])

我希望我的代码仍然受益于TypeScript,这样如果我的下一行是fizzBuzz.identity("not-fizz-not-buzz");,我甚至在代码执行之前就看到错误,并且应该看到自动完成建议。

e7arh2l6

e7arh2l61#

在这种情况下,您可以使用泛型:

class FizzBuzz<T extends string> {
  private allowed: T[];

  constructor(allowed: T[]) {
    this.allowed = allowed;
  }

  public identity(x: T) {
    return x;
  }
}

let fizzBuzz = new FizzBuzz<'fizz'|'buzz'>(["fizz", "buzz"])

fizzBuzz.identity("not-fizz-not-buzz"); // Error

如果在编译时不知道allowed的值,则这是不可能的
如果您担心重复,那么您可以让TS为您做一些工作:

class FizzBuzz<T> {
  private allowed: readonly T[];

  constructor(allowed: readonly T[]) {
    this.allowed = allowed;
  }

  public identity(x: T) {
    return x;
  }
}

const allowed = ["fizz", "buzz"] as const; 
// allowed is now of type readonly [ 'fizz', 'buzz' ]
let fizzBuzz = new FizzBuzz<typeof allowed[number]>(allowed);
// typeof allowed[number] should be 'fizz'|'buzz' 

fizzBuzz.identity("not-fizz-not-buzz"); // Error
carvr3hs

carvr3hs2#

在第二个代码片段中,您可以在编辑代码时看到设计时的自动完成建议。但是,当不一定有任何代码编辑器打开时,您如何期望看到仅在运行时才知道的自动完成建议?
我能想象的最好的方法是记录一个包含建议的错误,你甚至不需要Typescript:

class FizzBuzz {
  constructor(allowed) {
    this.allowed = allowed;
  }
  identity(x) {
    if (this.allowed.includes(x))
      return x;
    else {
      var err = new Error(`Identity ${x} not allowed`);
      err.allowedIdentities = this.allowed;
      throw err;
     }
  }
}
let fizzBuzz = new FizzBuzz(["fizz", "buzz"]);
fizzBuzz.identity("not-fizz-not-buzz");

运行此命令时,将记录以下错误:

Error: Identity not-fizz-not-buzz not allowed
    at FizzBuzz.identity (C:\nodejs\test.js:9:17)
    at ... {
  allowedIdentities: [ 'fizz', 'buzz' ]
}

**(在阅读apokryfos的回答后添加:)**当确切的字面量已知时很重要。你写“当类用于示例化对象时”,这是否意味着

  • 当代码被 * 写 * 示例化类或
  • 当执行示例化类的代码时,例如new FizzBuzz(getListOfLiterals())

在第一种情况下,apokryfos的方法是可取的,但它不能处理第二种情况。

相关问题