Friday 3 June 2022

Python Type Hints and DI

After some initial reluctance I've started to use Python type hints for any non trivial code. I'm not strict at all (usually I don't declare all types, only when they are meaningful to me), and most times I don't enable the type checker (in vscode-pylance), I just want the sort of documentation that type declarations provide, and the improved intellisense experience. Somehow type hints in python seem much better to me than using typescript over javascript.

I've found something really interesting. We know that type hints are not enforced by the Python runtime (so Python remains as dynamic as always), they are intended to be used by third party tools before you run your code. This said, the interesting discovery to me is that the type information is available at runtime in form of annotations. So while the runtime won't impose any resctrictions based on these annotations, your code can use this information. In python 3.10 it's available through inspect.get_annotations(). I guess this is how the diffeent Dependency Injection libraries that have flourished in recentyears work.

This reminds me of how Dependency Injection works in Angular with TypeScript. So far, In JavaScript we don't have a standard way (like annotations) to add information (metadata) to our objects, but there is a proposal, the reflect-metadata api, and angular-polyfill.js takes care of adding it to our browser. If you add to your tsconfig.json file the emitDecoratorMetadata option (that also needs the experimentalDecorators option), TypeScript will save type information as metadata in the generated JavaScript (it generates code that adds this information to Reflect.metadata if the API exists). Example of generated JavaScript code:


var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);


__decorate([
    deco,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [String]),
    __metadata("design:returntype", void 0)


As explained here TypeScript will only do this for classes, functions... that have been decorated (with any decorator, you can just create a dummy one). You have a pretty nice explanation of how DI works in Angular-TypeScript here.

No comments:

Post a Comment