I have something that looks like this.
export enum TableCellType {
Index = 'index',
Text = 'text',
Template = 'template',
}
export interface TableCell {
class?: string;
}
I want the TableCell
interface to make one of the values in the enum required, but if one is on the object, then disallow others.
Example:
let a = {index: 2, text: 'hello'}
This is not OK because two of the values from the enum is on the object. Only one can exist at any given time.
let b = {text: 'This works'}
This is ok since there are not multiple from the enum.
How do I go about typehinting this so that typescript understands?
Thanks.
CodePudding user response:
You can get it working for object literals (in addition, I specified the type for properties defined by TableCellType):
export enum TableCellType {
Index = 'index',
Text = 'text',
Template = 'template',
}
type OneOfTableCellTypes = {index: number; text?: never; template?: never}
| {index?: never; text: string; template?: never}
| {index?: never; text?: never; template: string}
export type TableCell = OneOfTableCellTypes & {
class?: string;
}
let a: TableCell = {index: 2, text: 'hello'} // ERROR
let b: TableCell = {index: 2} // OK
If you have more variants, you can go with:
type TableCellTypeMap = {
index: number;
text: string;
template: string,
}
type ExcludeAllExcept<T, K extends keyof T> = {[Prop in keyof T]?: Prop extends K ? T[Prop]: never}
type oneOf<T> = { [K in keyof T]: Pick<T, K> & ExcludeAllExcept<T, K>}[keyof T];
export type TableCell = oneOf<TableCellTypeMap> & {
class?: string;
}
let a: TableCell = {index: 2, text: 'hello'} // ERROR
let b: TableCell = {index: 2} // OK
Unfortunately, this wont prevent you from assigning an incorrect object (having 2 properties) in runtime.