Last active
August 12, 2020 00:00
-
-
Save jahredhope/c9f863065711249009da5bedd517b969 to your computer and use it in GitHub Desktop.
Example: Conditionally require minimum data for calls based on first parameter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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