To achieve this, you can utilize mapped types in TS2.8 to make properties required or optional. Here's a generic example:
// Require<T, K> makes specified keys in object type T required
type Require<T, K extends keyof T = keyof T> = Pick<T, Exclude<keyof T, K>> &
Required<Pick<T, K>>
// Optionalize<T, K> makes specified keys in object type T optional
type Optionalize<T, K extends keyof T = keyof T> = Pick<T, Exclude<keyof T, K>> &
Partial<Pick<T, K>>
These mapped types complement each other using built-in functions like Pick
, Partial
, and custom conditional types. The idea is to separate properties with and without specified keys, modify accordingly, then reconstruct the type. You can test it as follows:
// Interface for testing
interface AnInterface {
req1: string;
readonly req2: number;
readonly opt1?: boolean;
opt2?: object;
}
// Test the Require mapping
type SomeRequired = Require<AnInterface, "req1" | "opt1">;
// type SomeRequired = { ... }
// Test the Optionalize mapping
type SomeOptional = Optionalize<AnInterface, "req1" | "opt1">;
// type SomeOptional = { ... }
Once tested successfully, you can apply these mappings to your specific object types and key names. Good luck!
Link to code