Here's a utility that will allow you to guard against key of an object.
// Utility type to exclude specific types from a union
type ExcludeFromUnion<T, U> = T extends U ? never : T;
// Generic type that excludes a specified type U from the properties of T
type ExcludeTypeProperties<T, U> = {
[K in keyof T]: ExcludeFromUnion<T[K], U>;
};
/**
* Example usage:
* type Address = { postcode: string | null | undefined };
* type Book = { iban: string | null | undefined };
* const address = { postcode: "abcd" } as Address;
* const book = { iban: "1234" } as Book;
*
* if (guardObjectProperty(address, "postcode", null)) {
* type A = typeof address; // { postcode?: string | undefined; }
* }
*
* if (guardObjectProperty(book, "iban", undefined)) {
* type B = typeof book; // { iban: string | null; }
* }
* }
*
* if (guardObjectProperty(address, "postcode", "")) {
* type C = typeof address; // { postcode?: null | undefined; }
* }
*
* @param object
* @param key
* @param includeType
* @returns
*/
export const guardObjectProperty = <T, K extends keyof T, U>(
object: T,
key: K,
excludeType: U
): object is ExcludeTypeProperties<T, U> =>
typeof object[key] !== typeof excludeType;
How do we use it?
type Address = { postcode?: string | null | undefined };
type Book = { iban: string | null | undefined };
const address = { postcode: "abcd" } as Address;
const book = { iban: "1234" } as Book;
if (guardObjectProperty(address, "postcode", null)) {
type A = typeof address; // { postcode?: string | undefined; }
}
if (guardObjectProperty(book, "iban", undefined)) {
type B = typeof book; // { iban: string | null; }
}
if (guardObjectProperty(address, "postcode", "")) {
type C = typeof address; // { postcode?: null | undefined; }
}
Note: if you make your key?:
optional and then attempt to remove undefined
it won't let you.
if (guardObjectProperty(address, "postcode", undefined)) {
type A = typeof address; // { postcode?: string | null | undefined; }
}
!
. – Storied