Property 'splice' does not exist on type 'T'

Viewed 1131

I am working with typescript and I encountered an error Property 'splice' does not exist on type 'T'.

type Item = {
  name: string,
  body: string,
  imgOne: string,
  imgTwo: string,
}[]
// In a different file, this function is present
interface Props<T> {
    className?: string;
    items: T
    setItems: Dispatch<SetStateAction<T>>;
    children?: ReactNode
} 

export const Carousel = <T extends object>({className, items, setItems, children}: Props<T>) => {
  console.log(items.splice(0,2));

  return <div /> 
}

// I am calling this function in a 3rd file.
export const HomeCarousel: FC = () => {
    const {Root} = useStyles();
    const classes = useStylesClasses();

    const [items, setItems] = useState<Item[]>([
        {
            name: "Naruto1",
            body: "Dive into the world of shinobi to witness one of the greatest tales",
            imgOne: "/two.svg",
            imgTwo: "/one.svg",
        },
        {
            name: "Naruto2",
            body: "Dive into the world of shinobi to witness one of the greatest tales",
            imgOne: "/two.svg",
            imgTwo: "/one.svg",
        },
        {
            name: "Naruto3",
            body: "Dive into the world of shinobi to witness one of the greatest tales",
            imgOne: "/two.svg",
            imgTwo: "/one.svg",
        },
    ]);

    
    return (
        <Root>
            <Carousel<Item[]> setItems={setItems} items={items}>
                {items.map((item, index)=> {
                    return <CarouselItem name={item.name}/>
                })}
            </Carousel>
        </Root>
    )
}

The splice function isn't working, now on one hand it makes sense since there is no splice in the type Item but shouldn't it work by default since it is an array?

Any help is appreciated!

1 Answers

Try replacing T extends object with T extends Array<unknown>.

This way you'll declare that T (in your case items: T) will always be some sort of array instead of a generic object. And hence TS will know that T will have .splice() method because it's "inherited" from Array.

UPDATE If that's not an option - you'll have to check that T or object is actually an array. Like so:

if (Array.isArray(items)) {
  console.log(items.splice(0, 2));
} else {
  throw "Expected items to be an array"
}

Or, if you want to use .splice() on any object in the future without having to check for it, you can use this: T extends { splice: Array<never>["splice"] }. It'll ensure that all types of objects will require you to define your own implementation of .splice() method which is compatible with the Array.splice() method.

Related