Symbols in TypeScript
In the following example we have doLog, that checks if a log properties exists on the passed in object. If yes, then it assumes it is a function and executes it.
function doLog(message: string, obj: any) { const objStr = obj.log ? obj.log(obj) : obj.toString(); console.log(`${message} ${objStr}`); } doLog("The first layer: ", layer);
That’s a bad, because we cannot guarantee that log is actually a logging function. The following example would break doLog:
const layer = { src: "dark.png", log: true // this will break doLog };
Another reasons why this is bad: If we iterated over the properties, log would show up, which is not what we want:
for (const key in layer) { if (layer.hasOwnProperty(key)) { const element = (layer as any)[key]; console.log(`${key}:${element}`); } }
We need to replace the property name log
with something unique, that no object can accidentally overwrite: A Symbol. First, we want a function that adds a logging string to any object we pass in:
// assume you are in a logging library const logHandler = Symbol(); function addLog<T>(obj: T, func: (obj: T) => string) { (obj as any)[logHandler] = func; }
Now we add the logging functionality to an object:
// in the package consumer const layer = { src: "dark.png", log: true }; addLog(layer, (obj: { src: string }) => `An image layer with src: ${obj.src}`);
Finally, when we run doLog we can be sure that log is a unique value, because we are using a Symbol.
function doLog(message: string, obj: any) { const objStr = obj[logHandler] ? obj[logHandler](obj) : obj.toString(); console.log(`${message} ${objStr}`); } doLog("The first layer: ", layer);