The key issue (pun intended) that we mentioned previously can actually easily be avoided by leveraging ECMAScript symbols, a new primitive type that was introduced with ES2015 and is now well supported in all modern web browsers.
Symbols are interesting because every single one of them is unique; you cannot create the same Symbol twice:
const foo: Symbol = Symbol(); const bar: Symbol = Symbol(); console.log(foo === bar); // false
In the preceding example, foo and bar are not the same! A symbol is a primitive type that can't be recreated, unlike strings and numbers, for example. However, it shares the immutability property of the other primitives: once a symbol has been created, it cannot be modified.
When creating a Symbol, you can pass in a description using a string or number. This description is optional and only useful for debugging. Setting a symbol description doesn't have any impact on its uniqueness:
const theAnswer = Symbol(42); const anotherAnswer = Symbol(42); // The following would fail to compile in TypeScript but would just return false in JavaScript // here's the TypeScript error it triggers: TS2367: This condition will always return 'false' since the types 'unique symbol' and 'unique symbol' have no overlap. //console.log(theAnswer === anotherAnswer); // false const mySuperSymbol = Symbol('This is a fantastic symbol');
Before symbols were introduced in ECMAScript 2015, only strings could be used as object keys, but now symbols can also be used:
const mySymbol = Symbol('foo'); const myObject = { [mySymbol]: 'baz', }; console.log(myObject[mySymbol]);
Actually, this usage pattern is the raison d'être of symbols: it provides us with a way to define unique object keys.related ones. Moreover, we'll become more versatile, given how powerful InversifyJS is compared to Vue's built-in DI support
Now that we know what symbols are, we can leverage them to add more safety to our previous DI code.
Instead of using the same string key on the provider and injection sides, we can define, export, and use Symbol. This will ensure that we get precisely the dependency that we care about and not another one.
We'll leave this as an exercise for you, but you'll see this technique being used in practice in the upcoming sections.