Skip to content

Instantly share code, notes, and snippets.

@ryangoree
Last active February 24, 2025 00:47
Show Gist options
  • Save ryangoree/9a49136080bbb91dcdd36c6f805d5413 to your computer and use it in GitHub Desktop.
Save ryangoree/9a49136080bbb91dcdd36c6f805d5413 to your computer and use it in GitHub Desktop.
Experiment for dynamic interfaces
/**
* Construct a type based off T where TDefinedField is defined when
* T matches TDefinedState.
*
* @example
* ```ts
* type Payload = DefinedWhen<
* {
* isFetched: boolean;
* hasError: boolean;
* data: string | undefined;
* dataType: number | undefined;
* },
* "data" | "dataType",
* { isFetched: true; hasError: false }
* >;
*
* function handleResponse({
* isFetched,
* hasError,
* data,
* dataType,
* }: Payload) {
* data; // => string | undefined
* dataType; // => string | undefined
*
* if (isFetched === true && hasError === false) {
* data; // => string
* dataType; // => string
* }
* }
* ```
*/
type DefinedWhen<
T extends Record<string, any>,
TDefinedField extends keyof T,
TDefinedState extends Partial<T>,
> =
| (Omit<T, TDefinedField | keyof TDefinedState> &
TDefinedState &
Record<TDefinedField, Exclude<T[TDefinedField], undefined>>)
| {
[DefinedStateKey in keyof TDefinedState]: {
[K in keyof T]: K extends DefinedStateKey
? Exclude<T[K], TDefinedState[K]>
: T[K];
};
}[keyof TDefinedState];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment