TypeScript: check that the required properties of

2019-02-27 09:43发布

问题:

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?

回答1:

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);
    }
}


回答2:

the error message said property 'b' is optional in type '{ a: Date; b?: Date; }' but required in type '{ a: Date; b: Date; }'

It can be solve like this

myFunctionInternal(params as {a,b}); 

or

myFunctionInternal({a:params.a ,b:params.b});