'TypeScript: Function must return a single prop of object with unknow properties
The thing is, im trying to tell TypeScript that a method of a 'column' object called 'selector' recives a 'row' object with unknow properties, this method should return anything as long as belong to the 'row' object.
I'm using TypeScript v4.5.5
The problem
So far I tryed this:
type ColumnCommonProps = {
_index: number;
title: string;
selector: (row: {[key: string]: any}) => keyof typeof row;
};
The thing "works" but TypeScript it's not yelling when I want to, for instance:
const someRow = {
name: 'Jhon'
surName: 'Doe'
};
const column: ColumnCommonProps = {
_index: 0,
title: 'Last Name',
//trying to return a prop that does not exist in 'row' object
selector: (row: {[key: string]: any}) => row.lastName,
};
column.selector(someRow)
//TypeScript should trow something like "Property 'lastName' doesn't exist in row"
The rest of my code
I don't know if it's even possible to do a typing like this, however heres the whole react component interface
type ColumnCommonProps = {
_index: number;
title: string;
selector: (row: {[key: string]: any}) => keyof typeof row;
};
type ColumnTruncateType =
| {
sortable?: false;
sortMethod?: never;
}
| {
sortable: true;
sortMethod?: () => undefined;
};
type ColumnType = ColumnCommonProps & ColumnTruncateType;
export interface ISuperTableProps {
columns: ColumnType[];
rows: {}[];
title?: string;
defaultSortMethod?: () => undefined;
exportable?: boolean;
pagination?: boolean;
searcher?: boolean;
}
Solution 1:[1]
You can use a generic type to define the selector
type ColumnCommonProps<T> = {
_index: number;
title: string;
selector: (row: T) => keyof T
};
type someRowNeeded = {
name: string;
surName: string;
lastName: string
}
const someRow = {
name: 'Jhon'
surName: 'Doe'
};
const column: ColumnCommonProps<someRowNeeded> = {
_index: 0,
title: 'Last Name',
selector: (row: {[key: string]: any}) => row.lastName,
};
column.selector(someRow) //Error! 'lastName' is declared here.
Here then wherever you interface with the user of the library you have to take the generic shape of the row. Basically you'll have to pass the generic around.
type ColumnCommonProps<T extends Record<string, any>> = {
_index: number;
title: string;
selector: (row: T) => keyof T
};
type ColumnTruncateType =
| {
sortable?: false;
sortMethod?: never;
}
| {
sortable: true;
sortMethod?: () => undefined;
};
type ColumnType<T extends Object> = ColumnCommonProps<T> & ColumnTruncateType;
type ISuperTableProps<T> = {
columns: ColumnType<T>
rows: T[]
title?: string;
defaultSortMethod?: () => undefined;
exportable?: boolean;
pagination?: boolean;
searcher?: boolean;
}
function createISuperTable<T extends Object>(props: ISuperTableProps<T>) {
//your implemntation here
}
You can also strictly type the object return value and title to be of specific values using string delimiters and string literals, but perhaps that's out of the scope of this question.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
