I'm working in a project that uses a generator to pull in interfaces from a GraphQL schema. We use a pattern in the project where we create our Component interfaces from the GraphQL schema interfaces that are generated for queries that the components make for data (so the props power the queries that power the components). From these GraphQL interfaces, I often need to customize my component interface since some fields may be required, others optional, and others removed because they're hardcoded.
For the props on a current component, I have a situation I haven't run into before. In this case, only one of the fields in the GraphQL schema interface is required, another is hardcoded internally (so should be excluded from my component props), and the rest are all optional. I'll simplify the classes for the sake of not adding any complexity to an already seemingly complex usecase.
Generated GraphQL Interface type (the base type to create the Component interface from):
MyBaseInterface: {
prop1: string;
prop2: string;
prop3: string;
prop4: string;
prop5: string;
prop6: string;
}
I want to create an interface type using the base generated interface. The desired component interface should look like this:
MyComponentInterface: {
prop1!: string;
prop2!: string;
prop4?: string;
prop5?: string;
prop6?: string;
}
Notice how prop3
is removed, prop1
& prop2
are required, and the rest of the props are optional? Most of the values get defaulted in the component for backward compatibility with earlier implementations. The new Component interface should always be based on the MyBaseInterface, and the Component interface is expected to change over time.
My team typically uses the typing utils from TypeScript library for creating component types, but this usecase goes a ways beyond the basic scope of what TS provides in their utils. We have usually just needed stuff like:
export type MyNewInterface = Pick<MyBaseInterface, 'prop1' | 'prop2' | 'prop4'>;
But my current case is more complex than just picking some required fields - it has some required fields, but also has removals, and needs the rest of the fields to remain optional. The TypeScript advanced typing docs seemed promising, but still didn't quite deal with a usecase like this.
I'm still rather new to TypeScript of this depth, and haven't found this usecase in SO yet (apologies if my few dozen searches just missed such an answer). I found things that were similar, but limited to either optional properties with removal of a few or optional properties with requiring a few, but nothing that combined them all together into one that could specify required fields, excluded fields, and leave the rest optional. I just found stuff like:
- Union-ing with exclusions
- Property Exclusions
- New Type with Single Optional Property
- New Type with Multiple Optional Properties
I would like to have a method that works something like this to create my Component interface:
export type MyComponentInterface = OptionalRequiredRemoved<MyBaseInterface, 'prop1' | 'prop2', 'prop3'>;
Hopefully that makes sense. Any help is appreciated. Thanks!