is not assignable to type IntrinsicAttributes - reactjs

I'am working on a next.js project where i pass data from getStaticProps to the main component and when i try to pass it to the children i get an error saying that the data i try to pass are not assignable: here is the code:
the data :
export async function getStaticProps() {
let articlesArray: articleCard[] = []
const data = await getArticlesList().then((response) => {
return response
})
if (data) {
articlesArray.push(...data)
}
return {
props: {
articlesArray
}
}
}
Then i get it in the main component:
export default function Blog(props: { articlesArray: articleCard[] }) {
const articlesList = props.articlesArray
return (
<div className='container'>
<ArticleList articleList={articlesList} />
</div>
)
}
then the component that will use the data:
function ArticleList({articleList}: articleCard[]) {
const [currentPage, setCurrentPage] = useState<number>(1)
const [articlesPerPage] = useState<number>(6)
return (
<h1> rest of the code </h1>
)
}
for info:
the cardArticle type is as follows:
export interface fields {
title: string
slug: string
content: [Object]
excerpt: string
coverImage: [Object]
date: string
author: [Object]
categories: []
}
export interface articleCard extends fields {
id: string
}
the errors:
at ArticleList: Property 'articleList' does not exist on type 'articleCard[]'.
at Blog on the ArticleList component:
Type '{ articleList: articleCard[]; }' is not assignable to type 'IntrinsicAttributes & articleCard[]'.
Property 'articleList' does not exist on type 'IntrinsicAttributes & articleCard[]'.

Related

How pass object's array in parameter to component in react?

I'm new to typescript and I have this trivial error.
(property) data: menuItems[]
Type '{ data: menuItems[]; }' is not assignable to type 'IntrinsicAttributes & menuItems[]'.
Property 'data' does not exist on type 'IntrinsicAttributes & menuItems[]'.ts(2322)
Here is code:
https://codesandbox.io/s/data-is-not-a-function-ju21g6?file=/src/Settings.tsx
And here is another combined with the first one
https://codesandbox.io/s/data-is-not-a-function-ju21g6?file=/src/TreeSettings.tsx:256-320
interface IMenuItems {
name: string;
level: number;
id: number;
pid: number;
children?: any[];
}
const Settings = () => {
const { flattenarr, zerotreetoarr } = useConvertTree();
const [data, setData] = useState<menuItems[]>([]);
useEffect(() => {
zerotreetoarr(tree.children as [], [0]);
setData(flattenarr);
}, []);
return <TreeSettings data={data} />;
};
export interface IMenuItems {
name: string;
level: number;
id: number;
pid: number;
children?: any[];
}
const TreeSettings = (data: menuItems[]) => {
return (
<>
{data.map((t) => {
return <div>{t.name}</div>;
})}
</>
);
};
The problem in Settings.tsx at <TreeSettings data={data} />; on data I get
(property) data: menuItems[]
Type '{ data: menuItems[]; }' is not assignable to type 'IntrinsicAttributes & menuItems[]'.
Property 'data' does not exist on type 'IntrinsicAttributes & menuItems[]'.ts(2322)
How do I pass the data in the prop with types ?
U cant use interface as type parameter, but u can use typeof IMenuItems like this:
const TreeSettings = (data:typeof
menuItems[]) => {
return (
<>
{data.map((t) => {
return <div>{t.name}</div>;
})}
</>
);
};
Function components are defined like so in Typescript:
import type { FC } from "react";
...
const TreeSettings: FC<{data: menuItems[]}> = ({data}) => {
...
}
FC stands for Function Component. It is a generic type that allows you to define the type of props, in this case {data: menuItems[]}. You can then destructure the props, in this case: ({data}), and the correct type will be inferred.
Fixed sandbox: https://codesandbox.io/s/data-is-not-a-function-forked-spp0xn?file=/src/TreeSettings.tsx
In your case you were not destructuring the props object. Instead you declared the entire props object to have type menuItems[] which is incorrect.
This line:
<TreeSettings data={data} />;
is equivalent to
TreeSettings({data: data})
This passes an object with a data property to the Function Component.
It does not pass the array as the parameter.

Return type based on parameter value

My goal is to have different type for different parameter type
Here is my code
import React from "react";
type Response<T> = {
data: T;
description: string;
date: string;
};
type Data = {
title: string;
name: string;
};
type DataWidthLabel = Data & { labels: string };
type Endpoint = "endpoint_1" | "endpoint_2";
type FnResponse<T> =
T extends "endpoint_1" ? Response<Data> :
T extends "endpoint_2" ? Response<DataWidthLabel> : never;
type Props = {
endpoint: Endpoint;
children: (data: Response<Data> | Response<DataWidthLabel>) => void;
};
function queryFunction<T extends Endpoint>(endpoint: T): FnResponse<T> {
if (endpoint === "endpoint_1") {
return {
data: {
title: "title",
name: "name"
},
description: "description",
date: "date"
} as FnResponse<T>;
}
return {
data: {
title: "title",
name: "name",
labels: "labels"
},
description: "description",
date: "date"
} as FnResponse<T>;
}
const DataComp: React.FC<Props> = ({ endpoint, children }) => {
// queryFunction takes a type argument (<myType>) to type the data response
const data = queryFunction(endpoint);
return (
<div>
{children(data)}
<div>
<p>{data.description}</p>
<p>{data.date}</p>
</div>
</div>
);
};
const ParentComp1 = () => (
<DataComp endpoint="endpoint_1">
{(data) => {
return data.data.name;
}}
</DataComp>
);
const ParentComp2 = () => (
<DataComp endpoint="endpoint_2">
{(data) => {
return data.data.labels;
}}
</DataComp>
);
export default function App() {
return (
<div className="App">
<ParentComp1 />
-----
<ParentComp2 />
</div>
);
}
I'm not able to fix error for the case return data.data.labels;
If you make Props generic, then you can say that the parameter in data must be the FnResponse of the endpoint field:
type Props<E extends Endpoint> = {
endpoint: E;
children: (data: FnResponse<E>) => void;
};
Also, you could change FnResponse to a lookup table instead:
type FnResponse<T extends string> = Response<({
"endpoint_1": Data;
"endpoint_2": DataWidthLabel;
} & { [key: string]: never })[T]>;
Lastly, the component itself needs to be generic so we can pass down the generic parameter to Props:
function DataComp<E extends Endpoint>({ endpoint, children }: Props<E>) {
or
// NO React.FC!
const DataComp = <E extends Endpoint>({ endpoint, children }: Props<E>) => {
Playground

HOC - Type '{...}' is not assignable to type 'IntrinsicAttributes & PropType'

Hi I'm getting this error :
Type '{ children: Element; onClickOutside: () => void; }' is not assignable to type 'IntrinsicAttributes & PopUpWrapperProps'.
Property 'children' does not exist on type 'IntrinsicAttributes & PopUpWrapperProps'.ts(2322)
when trying to use <PopUpWrapper> in InfoIcon.tsx, I'm guessing it comes from a bad typing in withPortal.tsx but I tried many things and didn't get the error to disappear...
Do you have any idea on how to solve this ?
Files :
withPortal.tsx
const withPortal = <P extends object>(Component : React.ComponentType<P>, querySelector = "#portal") => (props : P) => {
const isMounted = useMounted(null)
return isMounted && ReactDOM.createPortal(
<Component {...props}/>,
document.querySelector(querySelector)
)
}
export default withPortal
PopUpWrapper.tsx
interface PopUpWrapperProps {
onClickOutside: () => void
}
const PopUpWrapper : React.FC<PopUpWrapperProps> = ({children, onClickOutside}) => {
...
return <div className={styles.popup_wrapper} ref={ref} onClick={handleClick}>
{children}
</div>
}
export default withPortal(PopUpWrapper)
InfoIcon.tsx
interface InfoIconProps {
src: string,
alt: string
className?: string,
isProtected?: boolean
}
const InfoIcon : React.FC<InfoIconProps> = ({
src, alt, children, className = "", isProtected = true
}) => {
...
return <div className={styles.info_icon}>
...
{
identity === Identity.Testing &&
<PopUpWrapper onClickOutside={cancelIdendityTest}> //error here
<IdentityPopup />
</PopUpWrapper>
}
</div>
}
export default InfoIcon;
Just add children to your props type:
interface PopUpWrapperProps {
onClickOutside: () => void,
children: any
}

how can i give type in getServerSideProps of Nextjs with typescript?

I'm using NextJs + TypeScript to make a little clone project, but I got a problem with type in getServerSideProps.
As you can see, in getServerSideProps, I am fetching data using with context.query.
But some error message is not fixed and I don't understand why that error appears.
The error message is this.
Type 'string[]' cannot be used as an index type.ts(2538)
Type 'undefined' cannot be used as an index type.ts(2538)
const genre: string | string[] | undefined
How can I fix this type problem?
import Head from "next/head";
import Nav from "../components/Nav/Nav";
import Header from "../components/Header/Header";
import Results from "../components/Results/Results";
import requests from "../utils/requests";
import { GetServerSideProps } from "next";
type HomeProps = {
results: {}[];
};
export default function Home({ results }: HomeProps) {
console.log(results);
return (
<div>
<Results results={results} />
</div>
);
}
export const getServerSideProps: GetServerSideProps = async (context) => {
const genre = context.query.genre
const response = await fetch(
`https://api.themoviedb.org/3${
requests[genre]?.url {/*this is problem line*/}
|| requests.fetchTopRated.url
}`
);
const data = await response.json();
return {
props: { results: data.results },
};
};
You can use like this;
type PageProps = {
isAuthanticated: boolean,
categories?: CategoryType[]
}
export const getServerSideProps: GetServerSideProps<PageProps> = async (context) => {
const _props: PageProps = {
isAuthanticated: auth,
categories: data.results
}
return { props: _props }
};
const Category: NextPage<PageProps> = (props) => {
return(
...
)
};
Since the type of genre can be string or string[] (or undefined), it can not be used to index requests without being narrowed down to string via the use of an if statement:
if (typeof genre === 'string') {
// Typescript now knows it is a string
const response = await fetch(
`https://api.themoviedb.org/3${
requests[genre]?.fetchTopRated.url {/*this is problem line*/}
|| requests.fetchTopRated.url
}`
);
const data = await response.json();
return {
props: { results: data.results },
};
} else if (typeof genre == 'object'){
// handle case where it is an array
} else {
// genre is undefined
}
When you receive params via context, the value could be either string or string[] (or undefined) so you need to cast. It could be a single genre or multiple genres in the URL.
?genre=film or ?genre=film&genre=music
For you case, simply cast as string:
const genre = context.query.genre as string;
UPDATE
As per your comments, the first issue that you raised in the question was actually about casting to string as above.
The second issue, which you should not actually be seeing and must be a TS or module config issue, is related to trying to accessing a key as string by index on your vanilla object exported from "../utils/requests";
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ fetchTrending: { title: string; url: string; }; ...
Your data object has literal key names:
// ../utils/requests
export default {
fetchTrending: {
title: "Trending",
url: /trending/all/week?api_key=${API_KEY}&language=en-US,
},
fetchTopRated: {
title: "Top Rated",
url: /movie/top_rated?api_key=${API_KEY}&language=en-US,
},
};
Rather define the type like this:
export interface IRequest {
[name: string]: {
title: string;
url: string;
};
}
const data: IRequest = {
fetchTrending: {
title: "Trending",
url: `/trending/all/week?api_key=${API_KEY}&language=en-US1`
},
fetchTopRated: {
title: "Top Rated",
url: `/movie/top_rated?api_key=${API_KEY}&language=en-US`
}
};
export default data;
or you could use a Record to have strongly typed keys:
type RequestNames = "fetchTrending" | "fetchTopRated";
export const records: Record<
RequestNames,
{
title: string;
url: string;
}
> = {
fetchTrending: {
title: "Trending",
url: `/trending/all/week?api_key=${API_KEY}&language=en-US1`
},
fetchTopRated: {
title: "Top Rated",
url: `/movie/top_rated?api_key=${API_KEY}&language=en-US`
}
};

TypeScript/React - destructuring from useContext throws an error

I'm trying to work with the useContext hook in a TypeScript/React app. So I created a context object with createContext and passed a sampleObject to the Provider's value prop. When I then try to destructure the properties from useContext, TypeScript throws an error for each property:
Property 'name' does not exist on type 'AppContextInterface | null'.
Property 'author' does not exist on type 'AppContextInterface | null'.
Property 'url' does not exist on type 'AppContextInterface | null'.
Here's the code:
interface AppContextInterface {
name: string;
author: string;
url: string;
}
const AppCtx = React.createContext<AppContextInterface | null>(null);
const sampleObject: AppContextInterface = {
name: 'Using React Context in a TypeScript App',
author: 'thehappybug',
url: 'http://www.example.com'
}
const App = () => (
<AppCtx.Provider value={sampleObject}>
<PostInfo />
</AppCtx.Provider>
);
const PostInfo = () => {
const appContext = useContext(AppCtx);
// typescript throws the errors on the next line
const { name, author, url } = appContext;
return (
<div>
Name: {name}, Author: {author}, url: {url}
</div>
);
}
Not sure what the problem is...
Since appContext can be null, you need to handle that case
const PostInfo = () => {
const appContext = useContext(AppCtx);
if (!appContext) return null;
const { name, author, url } = appContext;
return (
<div>
Name: {name}, Author: {author}, url: {url}
</div>
);
}

Resources