The type system in TypeScript is not primarily designed to mutate the types of variables, but it does utilize control flow analysis to narrow variable types within certain code blocks. However, until recently, there was no straightforward way to trigger such narrowing through functions like addProp()
.
With the introduction of assertion functions in TypeScript 3.7, developers now have a tool to create functions that guard against invalid states without returning a value. These assertion functions are relatively new and come with some limitations, as discussed in various GitHub issues.
One approach to achieve type narrowing with functions like addProp()
is to define an assertion function where the input type T1
gets asserted to the narrower type T1 & WithProp<T2>
. In this setup, if the input does not match the expected type, the function simply modifies the object to match that type by adding the necessary property.
function addProp<T1 extends object, T2>(
o: T1,
value: T2
): asserts o is T1 & WithProp<T2> {
(o as T1 & WithProp<T2>).foo = value;
}
This allows for the desired behavior when accessing properties:
let obj = { bar: 'baz' };
obj.foo; // error! Property 'foo' does not exist on type {bar: string}
addProp(obj, 123);
obj.foo; // okay
It's important to note that this type narrowing occurs due to control flow analysis, which resets upon reassignments. This means that directly reassigning values might result in unexpected errors related to type mismatches.
Overall, while this method represents a step towards incorporating mutations in the type system, there are still limitations to consider. Good luck experimenting with these concepts!
Link to code example