Reputation: 618
With TypeScript, I'm trying to create a Material-UI AutoComplete
component which gets the input value based on an objects property name -> obj[key]
However, the prop getOptionLabel
shows the following error:
Type '(option: T) => T[keyof T] | ""' is not assignable to type '(option: T) => string'.
The prop expects a string, and I understand that the value of the object's property might not be a string.
Question: Why is this error happening based on the below code, and how can I solve it?
The codesandbox link: https://codesandbox.io/s/mui-ts-generic-autocomplete-o0elk?fontsize=14&hidenavigation=1&theme=dark
Also the original code in case the codesandbox link does not reflect the original problem at some point:
import * as React from "react";
import { Autocomplete } from "@material-ui/lab";
import { TextField } from "@material-ui/core";
export const isString = (item: any): item is string => {
return typeof item === "string";
};
type AutoCompleteFieldProps<T> = {
selectValue: keyof T;
options: T[];
};
// Top films as rated by IMDb users. http://www.imdb.com/chart/top
const topFilms = [
{ title: "The Shawshank Redemption", year: 1994 },
{ title: "The Godfather", year: 1972 },
{ title: "The Godfather: Part II", year: 1974 },
{ title: "The Dark Knight", year: 2008 },
{ title: "12 Angry Men", year: 1957 },
{ title: "Schindler's List", year: 1993 },
{ title: "Pulp Fiction", year: 1994 }
];
const AutoCompleteField = <T extends {}>({
selectValue,
options
}: AutoCompleteFieldProps<T>): React.ReactElement => {
return (
<Autocomplete<T>
id={name}
options={options}
fullWidth
// Error here
getOptionLabel={(option) =>
isString(option[selectValue]) ? option[selectValue] : ""
}
renderInput={(params) => (
<TextField {...params} label="demo autocomplete" />
)}
/>
);
};
// error:
// Type '(option: T) => T[keyof T] | ""' is not assignable to type '(option: T) => string'.
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<AutoCompleteField<{ title: string; year: number }>
options={topFilms}
selectValue="title"
/>
</div>
);
}
Thanks in advance!
Upvotes: 9
Views: 16335
Reputation: 426
I got your code working with
getOptionLabel={(option) =>{
const val = option[selectValue];
return isString(val) ? val : ""
}
It appears the type guard didn't work well without using a variable directly.
Upvotes: 4
Reputation: 14891
Make option
type of any
(option: any
) did the trick
getOptionLabel={(option: any) =>
isString(option[selectValue]) ? option[selectValue] : ""
}
Upvotes: 2