Array of records definition - arrays

I've got a component that uses these types and interfaces
import { FC } from 'react';
enum fieldTypes {
Text = 'Text',
DateTime = 'DateTime',
Boolean = 'Boolean',
Integer = 'Integer'
}
type Metadata = Record<string, { type: fieldTypes, widget?: string }>;
interface MetadataProperties {
metaType: string;
metadata: Array<Metadata>;
dispatchSetProperty: (properties: any) => void;
}
const MetadataComponent: FC<MetadataProperties> = ({ metaType, metadata, dispatchSetProperty }) => {...}
When I try to do
const metadata = [
{
description: {
type: fieldTypes.Text
},
},
{
title: {
type: fieldTypes.Text
}
}
];
<MetadataComponent metaType="language_metadata" metadata={metadata} dispatchSetProperty={dispatchSetProperty}/>
The last line is showing an error
TS2322: Type '({ description: { type: fieldTypes; }; title?: undefined; } | { title: { type: fieldTypes; }; description?: undefined; })[]' is not assignable to type 'Record<string, { type: fieldTypes; widget?: string | undefined; }>[]'.   Type '{ description: { type: fieldTypes; }; title?: undefined; } | { title: { type: fieldTypes; }; description?: undefined; }' is not assignable to type 'Record<string, { type: fieldTypes; widget?: string | undefined; }>'.     Type '{ description: { type: fieldTypes; }; title?: undefined; }' is not assignable to type 'Record<string, { type: fieldTypes; widget?: string | undefined; }>'.       Property 'title' is incompatible with index signature.         Type 'undefined' is not assignable to type '{ type: fieldTypes; widget?: string | undefined; }'.
I don't understand what's wrong. I've declared metadata as an Array of Metadata why is it erroring?
Any explanation would be awesome :)

Related

TS error when passing myDecorator function as decorate prop to React Slate

I am getting the following TS error:
(property) decorate?: ((entry: NodeEntry<Node>) => BaseRange[]) | undefined
Type '([node, path]: [node: any, path: any]) => { anchor: { path: any; offset: string | number; }; focus: { path: any; offset: string; }; decoration: string; }[]' is not assignable to type '(entry: NodeEntry<Node>) => BaseRange[]'.
Type '{ anchor: { path: any; offset: string | number; }; focus: { path: any; offset: string; }; decoration: string; }[]' is not assignable to type 'BaseRange[]'.
Type '{ anchor: { path: any; offset: string | number; }; focus: { path: any; offset: string; }; decoration: string; }' is not assignable to type 'BaseRange'.
The types of 'anchor.offset' are incompatible between these types.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.ts(2322)
editable.d.ts(34, 5): The expected type comes from property 'decorate' which is declared here on type 'IntrinsicAttributes & { decorate?: ((entry: NodeEntry<Node>) => BaseRange[]) | undefined; onDOMBeforeInput?: ((event: InputEvent) => void) | undefined; ... 8 more ...; as?: ElementType<...> | undefined; } & TextareaHTMLAttributes<...> & MUIStyledCommonProps<...> & { ...; }'
This is happening on the decorate prop of my Editable component:
<Editable
decorate={myDecorator}
Here is a link to a codesandbox where the error is recreated on line 271:
https://codesandbox.io/s/react-typescript-forked-mwe14t?file=/src/App.tsx
index value is either string | number and offset accepts onlynumber which is why it is complaining. I needed to cast the index to number (Number(index) or +index) and then use it
const numberedIdx = Number(index);
const offsetVal = numberedIdx + urlLength;
return {
anchor: {
path,
offset: numberedIdx,
},
focus: {
path,
offset: offsetVal,
},
decoration: "link",
};

How to type provideTags in redux-toolkit (many items endpoint)

Following code works well, however I dont manage to type providesTags correctly:
type Post = {
id: number,
name: string,
description: string,
}
const postsApiSlice = api.injectEndpoints({
endpoints: (builder) => ({
getPosts: builder.query<EntityState<Post>, void>({
query: ROUTES.POSTS,
transformResponse: (responseData: Post[]) => {
return adapter.setAll(initialState, responseData)
},
// Typescript error is here, at provideTags
providesTags: (result) => {
// What to do if result is undefined?
if (!result) return [{ type: POST_TAG, id: 'LIST' }]
const tags = (result.ids.length > 0) ?
// Typescript accepts type of next line if I return it
result.ids.map((id) => ({ type: POST_TAG, id }))
:
// Typescript also accepts type of next line if I return it
[{ type: POST_TAG, id: 'LIST' }]
return tags
}
}),
}),
})
Typescript error I get:
Type '(result: EntityState<Post> | undefined) => { type: string; id: EntityId; }[]' is not assignable to type 'ResultDescription<"Post", EntityState<Post>, void, FetchBaseQueryError, {} | undefined> | undefined'.
Type '(result: EntityState<Post> | undefined) => { type: string; id: EntityId; }[]' is not assignable to type 'GetResultDescriptionFn<"Post", EntityState<Post>, void, FetchBaseQueryError, {} | undefined>'.
Type '{ type: string; id: EntityId; }[]' is not assignable to type 'readonly TagDescription<"Post">[]'.
Type '{ type: string; id: EntityId; }' is not assignable to type 'TagDescription<"Post">'.
Type '{ type: string; id: EntityId; }' is not assignable to type 'FullTagDescription<"Post">'.
Types of property 'type' are incompatible.
Type 'string' is not assignable to type '"Post"'.ts(2322)
endpointDefinitions.d.ts(188, 5): The expected type comes from property 'providesTags' which is declared here on type 'Omit<EndpointDefinitionWithQuery<void, BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError, {}, {}>, EntityState<Post>> & { ...; } & { ...; } & QueryExtraOptions<...>, "type"> | Omit<...>'
If I return just result.ids.map((id) => ({ type: POST_TAG, id })) or just [{ type: POST_TAG, id: 'LIST' }] works correctly.
How can I type it?
Also, not sure what should I do when result is undefined. Should I return [{ type: POST_TAG, id: 'LIST' }]?
This is described in typing providesTag/invalidatesTags.
You will need a few as const assertions when you define POST_TAG.
So not const POST_TAG = "foo", but const POST_TAG = "foo" as const should do the trick. Otherwise it will be typed as "string", not as "foo".

Redux toolkit and typescript

I am learning TS, and currently have a problem with the redux-toolkit in it.
I want to create a simple toggle for true/false value but got an error.
import { createSlice, PayloadAction } from "#reduxjs/toolkit";
import { BooleanLiteral } from "typescript";
const initialState = {
hidden: true,
};
const menuSlice = createSlice({
initialState,
reducers: {
setHidden: (state) => (state.hidden = !state.hidden),
},
});
error : ype '(state: WritableDraft<{ hidden: boolean; }>) => boolean' is not assignable to type 'CaseReducer<{ hidden: boolean; }, { payload: any; type: string; }> | CaseReducerWithPrepare<{ hidden: boolean; }, PayloadAction<any, string, any, any>>'.
Type '(state: WritableDraft<{ hidden: boolean; }>) => boolean' is not assignable to type 'CaseReducer<{ hidden: boolean; }, { payload: any; type: string; }>'.
Type 'boolean' is not assignable to type 'void | { hidden: boolean; } | WritableDraft<{ hidden: boolean; }>'.
The reason is that you are trying to return statement, you just need to change braces like this
setHidden: state => {
state.hidden = !state.hidden
}

Getting Typescript Error while adding object to array using useState in React

Result type prop is defined as follows. CalendarProp, ContactProp,... are predefined and all have different types.
type ResultProp =
| { type: "calendar", data: CalendarProp }
| { type: "contact", data: ContactProp }
| { type: "dropbox", data: DropboxProp }
| { type: "slack", data: SlackProp }
| { type: "tweet", data: TweetProp }
Calendar Prop
interface CalendarProp {
id: string,
title: string,
invitees: string,
date: string,
matching_terms: Array<string>
}
ContactProp type
interface ContactProp {
id: string,
name: string,
company: string,
emails: Array<string>,
phones: Array<string>,
last_contact: string,
matching_terms: Array<string>
}
All the props have a different type.
Component maintaining a result array is defined below. I am getting Typescript error while adding object to result array using useState hook.
Here calendarData.calendar, ... is an array of json object.
const SearchResults: React.FC<QueryProp> = (props) => {
const query = props.query;
const [result, setResult] = useState<Array<ResultProp>>([]);
useEffect(() => {
if (query.length > 0){
const files = [
{
type: "calendar",
data: calendarData.calendar
},
{
type: "contact",
data: contactData.contacts
},
{
type: "dropbox",
data: dropboxData.dropbox
},
{
type: "slack",
data: slackData.slack
},
{
type: "tweet",
data: tweetData.tweet
}
];
for(const file of files){
for(const d of file.data){
if (d.matching_terms.includes(query)) {
switch(file.type) {
case "calendar":
setResult([...result, { type: "calendar", data: d }]); // Error here
break;
}
}
}
}
}
return () => {
setResult([]);
}
}, [query])
return (
<div className="search-results">
{/* {result.map((r, index) => {
return <Cardview key={index} {...r} />
})} */}
</div>
)
}
I get the following error message:
Argument of type '({ type: "contact"; data: ContactProp; } | { type: "dropbox"; data: DropboxProp; } | { type: "slack"; data: SlackProp; } | { type: "tweet"; data: TweetProp; } | { ...; })[]' is not assignable to parameter of type 'SetStateAction<ResultProp[]>'.
Type '({ type: "contact"; data: ContactProp; } | { type: "dropbox"; data: DropboxProp; } | { type: "slack"; data: SlackProp; } | { type: "tweet"; data: TweetProp; } | { ...; })[]' is not assignable to type 'ResultProp[]'.
Type '{ type: "calendar"; data: { id: string; title: string; invitees: string; matching_terms: string[]; date: string; } | { id: string; name: string; company: string; emails: string[]; phones: string[]; matching_terms: string[]; last_contact: string; } | { ...; } | { ...; } | { ...; } | { ...; }; }' is not assignable to type 'ResultProp'.
Types of property 'data' are incompatible.
Type '{ id: string; title: string; invitees: string; matching_terms: string[]; date: string; } | { id: string; name: string; company: string; emails: string[]; phones: string[]; matching_terms: string[]; last_contact: string; } | { ...; } | { ...; } | { ...; } | { ...; }' is not assignable to type 'CalendarProp'.
Type '{ id: string; name: string; company: string; emails: string[]; phones: string[]; matching_terms: string[]; last_contact: string; }' is missing the following properties from type 'CalendarProp': title, invitees, date
Here you test that file coming from files match the calendar type. But you never said to TypeScript the type of files. It's not sure for him what d really is so it can be CalendarProp or ContactProp or... You have 2 solutions to fix that:
Declare the type of files:
const files: ResultProp[] = [
...
In this case, if file.type is "calendar", then TypeScript can deduce that data is of type CalendarProp.
Cast the value of d to CalendarProp:
setResult([...result, { type: "calendar", data: d as CalendarProp }]);

react-leaflet GeoJSON with typescript

I am pretty new using typescript with reactjs. Currently, the project I am working on is using a react-leaflet/leaflet specifically their GeoJSON component. I am running into a typescript error when I pass my data to the props.
I have been doing some research on this, even installed the geojson package and followed their examples, https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/geojson/geojson-tests.ts, tried everything that I know but no luck.
If I try to pass data as
const GeoJsonData: geojson.Feature<geojson.Polygon, geojson.GeoJsonProperties> = {
geometry: {
coordinates: [[
[20.7325804014456, -156.424372312952],
[20.7320799340775, -156.424348923897],
[20.732046895414, -156.425191022255],
[20.7321183621394, -156.425194200455],
[20.7321078658074, -156.425458542909],
[20.7325370751528, -156.425476608985],
[20.7325804014456, -156.424372312952]
]],
type: 'Polygon',
},
properties: {
name: 'some name'
},
type: 'Feature',
};
or
const GeoJsonData: = {
geometry: {
coordinates: [[
[20.7325804014456, -156.424372312952],
[20.7320799340775, -156.424348923897],
[20.732046895414, -156.425191022255],
[20.7321183621394, -156.425194200455],
[20.7321078658074, -156.425458542909],
[20.7325370751528, -156.425476608985],
[20.7325804014456, -156.424372312952]
]],
type: 'Polygon',
},
properties: {
name: 'some name'
},
type: 'Feature',
} as as geojson.GeoJsonObject;
I get this error
Conversion of type '{ properties: { name: string; } | { name: string; }; type: "Feature"; geometry: Polygon | null; id?: string | number | undefined; bbox?: BBox2d | BBox3d | undefined; }[]' to type 'GeoJsonObject' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.ts(2352)
Conversion of type '{ properties: { name: string; } | { name: string; }; type: "Feature"; geometry: Polygon | null; id?: string | number | undefined; bbox?: BBox2d | BBox3d | undefined; }[]' to type 'GeoJsonObject' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Property 'type' is missing in type '{ properties: { name: string; } | { name: string; }; type: "Feature"; geometry: Polygon | null; id?: string | number | undefined; bbox?: BBox2d | BBox3d | undefined; }[]' but required in type 'GeoJsonObject'.
But If I remove types from data. Then I get this error.
const GeoJsonData: = {
geometry: {
coordinates: [[
[20.7325804014456, -156.424372312952],
[20.7320799340775, -156.424348923897],
[20.732046895414, -156.425191022255],
[20.7321183621394, -156.425194200455],
[20.7321078658074, -156.425458542909],
[20.7325370751528, -156.425476608985],
[20.7325804014456, -156.424372312952]
]],
type: 'Polygon',
},
properties: {
name: 'some name'
},
type: 'Feature',
}
No overload matches this call.
Overload 1 of 2, '(props: Readonly<GeoJSONProps>): GeoJSON<GeoJSONProps, GeoJSON<any>>', gave the following error.
Property 'type' is missing in type '{ properties: { name: string; } | { name: string; }; type: "Feature"; geometry: Polygon | null; id?: string | number | undefined; bbox?: BBox2d | BBox3d | undefined; }[]' but required in type 'GeoJsonObject'.
Overload 2 of 2, '(props: GeoJSONProps, context?: any): GeoJSON<GeoJSONProps, GeoJSON<any>>', gave the following error.
Type '{ properties: { name: string; } | { name: string; }; type: "Feature"; geometry: Polygon | null; id?: string | number | undefined; bbox?: BBox2d | BBox3d | undefined; }[]' is not assignable to type 'GeoJsonObject'.
<Map
center={[props.centerMapCoordinates.lat, props.centerMapCoordinates.lng]}
zoom={props.centerMapCoordinates.zoom}
style={{ height: mapHeight }}
onMoveEnd={(event: any) => props.getZoomMap(event)}
>
<TileLayer url="https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}/"
/>
<GeoJSON
key={GeoJsonData}
data={GeoJsonData}
// data={GeoJsonData}
onEachFeature={(feature, layer) => {
layer.on('click', (e) => {
console.log(e.target.feature);
// new Field().doesIntersect(e.target.feature);
});
if (props.centerMapCoordinates.zoom > 16) {
layer.bindTooltip(feature.properties.name, {
direction: 'center',
permanent: true,
}).openTooltip();
} else {
layer.closeTooltip();
}
layer.bindPopup(feature.properties.name);
}}
/>
</Map>
Note: If I add as any to GeoJsonData it gets rid of the errors, but then does not make any sense to use typescript.
Does anyone familiar with this issue or knows how can I define geojson types?
Please let me know if you have any questions. I can provide more details if needed. Thank you in advance.

Resources