I'd like to have a function with a generic type T
which must be an object and must have at least a property named code
of type string
, and then use keyof T
to get all object keys.
Why is this invalid?
function TableView<T extends { code: string }>() {
return forwardRef<HTMLDivElement, { data: T[], columns: Columns<keyof T> }>(
(props, ref) => {
Error:
TS2344: Type 'keyof T' does not satisfy the constraint 'string'.
Type 'string | number | symbol' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
where:
export interface Column<T extends string> {
field: T;
label: string;
align?: "left" | "center" | "right"
format?: "number" | "integer" | "percent" | "timestamp" | "text"
backgroundColor?: (row: any) => string
}
type Columns<T extends string> = Column<T>[]
export default Columns
CodePudding user response:
Theoretically T
can have not only string
keys (number | symbol
are also allowed). If you want to pick only string
keys - you can use Extract utility:
const e = Symbol();
type Foo = {
a: string; // String-like name
5: string; // Number-like name
[e]: string; // Symbol-like name
};
type K1 = keyof Foo; // typeof e | "a" | 5
type K2 = Extract<keyof Foo, string>; // "a"
Extract<Type, Union>
Constructs a type by extracting fromType
all union members that are assignable toUnion
Another option suggested by @kaya3 is using string & keyof T
intersection.
CodePudding user response:
Just change extends string
to extends any
. It will give you the same result you're looking for. The problem is that keyof
can be typed as more than just a string.