Skip to content

Instantly share code, notes, and snippets.

@dorzepowski
Created August 26, 2021 06:06
Show Gist options
  • Save dorzepowski/fcd9e4d927fe2f1a49928d51d09ba6bf to your computer and use it in GitHub Desktop.
Save dorzepowski/fcd9e4d927fe2f1a49928d51d09ba6bf to your computer and use it in GitHub Desktop.
Typescript type which allow to set a value only on one from listed fields.
/**
* Make all properties in T optional except property with key U.
*
* @example
* type Example = OtherOptional<'a', { a: string; b: string; }> // { a: string; b?: never; }
*/
export type OtherOptional<U extends keyof T, T> = Pick<T, U> & Partial<T>;
/**
* Make all properties in T disallowed (type never) except property with key U.
*
* @example
* type Example = OtherDisallowed<'a', { a: string; b: string; }> // { a: string; b: never; }
*/
export type OtherDisallowed<U extends keyof T, T> = { [K in keyof T]: K extends U ? T[K] : never };
/**
* Make type that allows objects with only one property from type T and not the rest.
*
* @example
* type Example = OneOf<{ red: string, green: string }> //{red: string; green?: never} | {red?: never; green: string}
*
*
* const example: Example = { red: 'some text' green: 'some text' }
* ~~~~~~~
* // error TS2322: Type '{ red: string; green: string; }' is not assignable to type 'Example1'.
* // Type '{ red: string; green: string; }' is not assignable to type 'OtherDisallowed<"red", OtherOptional<"red", { red: string; green: string; }>>'.
* // Types of property 'green' are incompatible.
* // Type 'string' is not assignable to type 'never'.
*/
export type OneOf<T> = { [K in keyof T]: OtherDisallowed<K, OtherOptional<K, T>> }[keyof T];
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment