Skip to content

Instantly share code, notes, and snippets.

@jahredhope
Last active August 12, 2020 00:00
Show Gist options
  • Save jahredhope/c9f863065711249009da5bedd517b969 to your computer and use it in GitHub Desktop.
Save jahredhope/c9f863065711249009da5bedd517b969 to your computer and use it in GitHub Desktop.
Example: Conditionally require minimum data for calls based on first parameter
/**
* Conditionally require additional data for function calls based on first parameter
* Allows a union of possible interfaces that describe a minimum amount of data required
* Values not named may still be used and have no minimum amount of data
*
* Extending on the work by David Sheldrick in https://artsy.github.io/blog/2018/11/21/conditional-types-in-typescript/
*/
interface BaseShape {
name: string;
data?: Record<string, unknown>;
}
interface Circle extends BaseShape {
name: "circle";
data: {
radius: number;
[key: string]: unknown;
};
}
interface Rectangle extends BaseShape {
name: "rectangle";
data: {
height: number;
width: number;
[key: string]: unknown;
};
}
type DefinedShape = Circle | Rectangle;
const shapes: BaseShape[] = [];
type FilterByName<Shape, Name> = Shape extends { name: Name } ? Shape : never;
export function createShape<T extends DefinedShape["name"]>(
shapeName: T,
shapeProperties: FilterByName<DefinedShape, T>["data"]
): void;
export function createShape<T extends BaseShape["name"]>(
shapeName: Exclude<T, DefinedShape["name"]>,
shapeProperties?: BaseShape["data"]
): void;
export function createShape(
shapeName: BaseShape["name"],
shapeProperties?: BaseShape["data"]
) {
const shape = { name: shapeName, data: shapeProperties };
shapes.push(shape);
}
// SHOULD Pass
createShape("circle", { radius: 1 });
createShape("rectangle", { height: 3, width: 4 });
createShape("rectangle", { height: 3, width: 4, color: "red" }); // Additional fields
createShape("triangle", { height: 2 }); // Unknown shape
createShape("triangle"); // Unknown with no data
// SHOULD Error
// @ts-expect-error
createShape("circle", { height: 2, width: 3 });
// @ts-expect-error
createShape("circle", { banana: 2 });
// @ts-expect-error
createShape("rectangle", { radius: 5 });
// @ts-expect-error
createShape("rectangle", { height: 5 });
// @ts-expect-error
createShape("rectangle", {});
// @ts-expect-error
createShape("rectangle");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment