typescriptstrictnullchecks

TypeScript: check that the required properties of an argument are defined before passing it to a function call


This doesn't compile (playground):

function myFunction(params: {
    a: Date,
    b?: Date
}) {
    if (params.b) {
        myFunctionInternal(params); // ERROR!
    }
}

function myFunctionInternal(params: {
    a: Date,
    b: Date
}) {}

Is there a more elegant workaround than params as any?


Solution

  • The problem is that the type guard impacts just the type of the field (params.b will have the undefined removed) not the type of whole object (param will continue to have the type { a: Date, b?: Date })

    Not sure I would call it more elegant, but we can create a type guard that removes the undefined from a type field:

    type RemoveOptionalFromField<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & { [P in K]-?: T[P] }
    
    function notNull<T, K extends keyof T>(o: T | RemoveOptionalFromField<T, K>, key: K) : o is RemoveOptionalFromField<T, K> {
        return !!o[key];
    }
    
    function myFunction(params: {
        a: Date,
        b?: Date
    }) {
        if (notNull(params, 'b')) {
            params.b.getDate()
            myFunctionInternal(params);
        }
    }
    

    We could even create a version that takes any number of keys:

    function allNotNull<T, K extends keyof T>(o: T | RemoveOptionalFromField<T, K>, ...keys: K[]) : o is RemoveOptionalFromField<T, K> {
        return keys.every(k => !!o[k]);
    }
    function myFunction(params: {
        a?: Date,
        b?: Date
    }) {
        if (allNotNull(params, 'b', 'a')) {
            params.b.getDate()
            myFunctionInternal(params);
        }
    }