This post is part of a series about implementing type checking for a TypeScript-like language. In the last post we walked through the code for type checking a small fragment of the language, with only primitive literals, object expressions, and member expressions.
Since function definitions bind variables that can be used in the body of the function, we'll need to handle variable expressions like
An environment is a table mapping variable names to types. A binding is a single name-to-type entry in the environment. When type checking a function definition, we add a binding for each argument to the environment; when we encounter a variable in the function body, we look up its type in the environment; and we drop the new bindings after type checking the function, since they're no longer in scope.
A straightforward way to implement this is with "functional update": to add a binding to an environment, copy the old environment and add the new binding. The old environment is not affected, so when we're finished type checking the function we discard the new environment and go back to the using the old one.