Skip to content

Instantly share code, notes, and snippets.

@ryangoree
Last active September 14, 2023 21:55
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.
*/
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];
// =======================================================================================
// Example:
// ---------------------------------------------------------------------------------------
type Payload = DefinedWhen<
{
isFetched: boolean;
hasError: boolean;
data: string | undefined;
dataType: string | undefined;
meta: string | undefined;
},
"data" | "dataType" | "meta",
{ isFetched: true; hasError: false }
>;
function handleResponse({
isFetched,
hasError,
data,
dataType,
meta,
}: Payload) {
data; // string | undefined
// ^?
dataType; // string | undefined
// ^?
meta; // string | undefined
// ^?
if (isFetched === true && hasError === false) {
data; // string
// ^?
dataType; // string
// ^?
meta; // string
// ^?
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment