Flowtype: How to use compute method in Class

2019-08-30 08:41发布

问题:

I wanna visit the class property according the params as the following code:

class Commander {
  constructor() {}
  create() {}
  test() {}
  undo() {}
  redo() {}
  execute(...args): void {
    const command: string = args.slice(0);
    const rest: any[] = args.slice(1);
    this[command].apply(this, rest);
  }
}

But I got an error as below:

Cannot get this[command] because an indexer property is missing in Commander 1.

More info you can see the flowtype try.

If I make some stupid things, and please let me know!

Thanks!!

回答1:

Thanks your answer, but I wanna the code keep tidy, and I found the another solve Try. But use the any keyword, make the check no sense about the static check. – Cin

If you use any keyword that is the same as just turning flow off for anything that touches that variable.

"If you want a way to opt-out of using the type checker, any is the way to do it. Using any is completely unsafe, and should be avoided whenever possible." from Any

This is a safer way: (Try)

class Commander {
  $key: "create" | "test" | "undo" | "redo";
  $value: () => mixed
  constructor() {}
  create() {}
  test() {}
  undo() {}
  redo() {}
  execute(command, ...rest): void {
    this[command].apply(this, rest);
  }
}


回答2:

Because the property accessor you're using could be any string, Flow thinks you're trying to use your class instance as a map. To get around this, you need to do some sort of checking of the command variable before calling the instance methods. Here's my suggested way how to do it:

(Try)

class Commander {
  constructor() {}
  create() {}
  test() {}
  undo() {}
  redo() {}
  execute(...args): void {
    const command: string = args.slice(0);
    const rest: any[] = args.slice(1);
    switch(command) {
      case "test":
        this.test.apply(this, rest);
        break;
      case "undo":
        this.undo.apply(this, rest);
        break;
      case "redo":
        this.redo.apply(this, rest);
        break;
      default:
        throw new Error("Invalid command");
    }
  }
}

You could also replace the method.apply(this, rest) syntax with method(...rest) to keep things a little cleaner, but that's stylistic ands not very relevant to your question.