Typed commands
See original GitHub issueI’d like to add to #1412 and #1511 to propose a type-safe approach.
Problem:
Commands are currently heavily error-prone:
- You can misspell the type and it will silently never trigger in your app
- You can misinterpret the types
Part of this problem is caused by the ability to listen to multiple commands at once.
Proposal
Encourage type safety within Lexical core and user-created commands. Make it so that you can only listen to a specific command at once and this command is strictly type safe and provided by Lexical core.
execCommand<T>(type: Command<T>, payload: T): void;
registerCommand<T>(type: Command<T>, payload: (T) => void): void;
class Command<T> {
type: string;
constructor(type: string) {
this.type = type;
}
}
const formatTextCommand = new Command<string>('formatText');
new LexicalEditor().execCommand(formatTextCommand, 'bold');
new LexicalEditor().registerCommand(formatTextCommand, (format) => {
// bold
});
The generic type above, while seemingly unused, enables us to offer type safety for the payload.
[Optionally] We can do like transforms where we check for the command reference to ensure that we’re strictly referring to the same command, in which case we don’t even need the type.
class Command<T> {}
const formatTextCommand = new Command<string>();
Trade-offs
(+) It’s type safe (-) It’s more costly, we have to provide an instance for every single command (-) It more verbose, especially for some Lexical core/React. For most internal/real-life usages it should be equivalent though.
Issue Analytics
- State:
- Created a year ago
- Reactions:1
- Comments:7 (6 by maintainers)
Top GitHub Comments
We can’t use enums unfortunately, open source Lexical should work without them (we strip out types) and also I couldn’t get Flow enums working at all!
On iOS we do this:
Then anyone can add their own commands by doing:
and to use them, the type is CommandType, and the IDE will happily autocomplete
.deleteCharacter
or whatever.