Typescript interface objects to string array - javascript

i have a interface named UiDataUpdateFunction.In the code defined like this.
#Effect()
bulkCreateUIDataUpdateFunction$ = this.actions$.pipe(
ofType<UIDataUpdateFunctionActions.BulkCreateUIDataUpdateFunction>(
UIDataUpdateFunctionActions.ActionTypes.BulkCreateUIDataUpdateFunction
),
mergeMap((action) => {
const params = {
body: action.payload.uiDataUpdateFunctions
};
return this.UIDataUpdateFunctionApi.bulkCreate(params).pipe(
mergeMap((uiDataUpdateFunctions: UiDataUpdateFunction) => {
console.log(uiDataUpdateFunctions)
this code's console log objects in array.
I want it should be return as string array. When i tried define like this uiDataUpdateFunctions: UiDataUpdateFunction[] its give a an error (The independent variable of type 'OperatorFunction<UiDataUpdateFunction[], Action>' cannot be assigned to a parameter of type 'OperatorFunction<UiDataUpdateFunction, Action>'. The type 'UiDataUpdateFunction[]' is missing the following properties of type 'UiDataUpdateFunction': id, projectId, uiDataStoreId.). So i tried do it like this
mergeMap((uiDataUpdateFunctions: UiDataUpdateFunction[]= [{
id: '',
projectId: '',
uiDataStoreId: '',
}])
but its still give same error.I also tried doing .map() to convert to array on uiDataUpdateFunctions. Probally i can't write correctly. Shortly i want to return objects coming from the interface as a string array. What should i do for this ?

Related

Array list is shown, array length is 0 and elements are undefined in react

So, basically i have two api calls in two different functions that are called from a single component page. The await function is applied to each of them because each of the response provided from the first api is used as params to the second api. for the first api call, inside the function, the response is pushed to the array named all_countries.
const apiCall = getCountry(req)
.then((response) => {
all_countries.push(...response);
dispatch(actionSuccess(NICE_ONE, response));
})
.catch((error) => {
dispatch(actionFailure(NICE_ONE, error));
});
each of the array objects inside all_countries is to be mapped and value(i.e country code present inside each object from all_countries) is used to call another api to get the response but my problem is upon console logging the all_countries from the second function, it shows the symbol of empty array. upon opening the array, it lists all the countries. when i console log the length of the array, it shows 0 and upon console logging the elements like all_countries[0], it shows undefined. Why is this happening? Could someone help me out please?
This gets shown on console
Upon expanding, this is shown:
enter image description here
So, i found that on adding all_countries.push, intellij shows me a warning, response is not an array type but rather AllCountryRes type.
AllRelaysRes type is defined as:
export type AllRelaysRes = {
logo: string;
ipv4: string;
ipv6: string;
port: string;
location: {
id: number;
ip: string
};
};
and the getCountry function is like this:
export const getCountry = (url: string): Promise<AllRelaysRes> => {
ExternalApi.setBaseUrl(url);
return ExternalApi.apiCall<AllRelaysRes>({
method: "GET",
url: "something",
});
};
The response from the api is an array of objects. I am just a beginner with typescript and trying out stuffs. My question is how do i make the response type as an array of object AllRelayRes? Doesnot return ExternalApi.apiCall angular brackets AllRelayRes mean that the response expected is an array of AllRelayRes since, AllRelayRes is kept inside the angular brackets? How do i fix this? Is this the real problem why i get the array length 0?
I believe you're dealing with a collection of objects of type AllRelayRes, not an array. It shows as [] in the console, but that represents a collection.
If you want to use it as an array, specify the type in your function <AllRelaysRes[]>
export const getCountry = (url: string): Promise<AllRelaysRes[]> => {
ExternalApi.setBaseUrl(url);
return ExternalApi.apiCall<AllRelaysRes[]>({
method: "GET",
url: "something",
});
};
Then you should be able to manipulate the data in an array format
If you want to keep it as a collection, you can probably iterate through them with
let x, key, obj
for(x in AllRelayRes) {
key = x; // 0, 1, 2 .. the index
obj = AllRelayRex[x] // the object
// country_name = AllRelayRex[x].country_name, etc
}

Specifying types with TypeScript, when <Array> has different kinds of structure

I am kind of new to TypeScript and I am trying to get rid of all any types.
Problem:
Within the React Component, I loop over an array of objects and extract a key/value pair.The components receives tags, tagKeys props as follows:
tags: [{ name: "Some tag" }] OR [{ platform: { name: "Some tag" } }];
tagKeys: ["name"] OR tagKeys: ["platform", "name"]
If I run this script (below), I get this error in the console:
Element implicitly has an 'any' type because index expression is not of type 'number'
type Props = {
tags: any[];
tagKeys: string[];
};
const Tags: React.FC<Props> = ({ tags, tagKeys }: PropsWithChildren<Props>) => {
const renderTags = (): React.ReactNode => {
return tags.map(tag => {
let key = "";
// Loop through tagKeys in the tags array to extract the tag
for (let i = 0; i < tagKeys.length; i++) {
key = i === 0 ? tag[tagKeys[i]] : key[tagKeys[i]];
}
return <Tag key={`tag-${key}`} tag={key} />;
});
};
return <StyledTags>{renderTags()}</StyledTags>;
};
If I change the line inside the for loop to...
key = i === 0 ? tag[tagKeys[i] as any] : key[tagKeys[i] as any];
...the script runs but I want to get rid of the any type.
Question:
Is there a way to set the type without specifying how the received props array tags will look?
I want to be able to pass arrays with different kinds of structure and extract a key/value pair.
There two issues to watch that we'll need to be clear about.
First, you asked:
Is there a way to set the type without specifying how the received props array tags will look?
type Props = {
tags: any[]; // This is the answer to your direct question
tagKeys: string[];
};
Secondly, having handled the above, TypeScript is actually complaining about your index.As you'll agree, reactjs uses the unique key to render each <Tag>.
// TypeScript is actually warning you about this.
// Note that initially, `key` is of type `string` (implicitly or indirectly )
let key = "";
// Within your loop, you assign `key` to be of type `object`
key = i === 0 ? tag[tagKeys[i]] : key[tagKeys[i]];
// So the above line says that `key` can be `string` or `object`
// Thus TypeScript tells you that...
// implicitly your index (key) expression is of type any
To handle that TypeScript error, update as follows:
let key: any = "";
Kindly make the necessary updates, and let me know how it goes for you.
key can be either a string or an object during it's lifetime, so my first intuition would be to declare it as such:
let key: object | string = "";
But TS is not happy with that, so my second try would be:
type NestedObject = { [key: string]: NestedObject } | string
let key: NestedObject = '';
key = { platform: { name: 'dd' } }
key = key.platform.name
But TS is not happy with the last line either, so at this time I would just give up:
let key: any = '';

Flow: Object type incompatible with Array<mixed>

I don’t understand the flow error I’m currently getting. I have a Javascript object of objects (dataObject) that I want to convert to an array of objects, so I do so using Object.values(dataObject). Then, I iterate through each object in the array with the following:
const dataObjectArray = Object.values(dataObject);
return dataObjectArray((data: DataObject) => {
const { typeA, typeB } = data;
return {
TYPE_A: typeA,
TYPE_B: typeB,
};
});
But I get the following flowtype error:
I’m not sure how to match up the types. Currently my DataObject flow type is
type DataObject = {
typeA: string,
typeB: string,
};
Any help would be appreciated. Thanks!
The type definition for the Object.values function has no way to know that the argument passed to it is an object where the values are all the same type. You could just as easily be doing Object.values({foo: 4, bar: "str"}). The type definition is
(any) => Array<mixed>
meaning that you are doing .map on a value of type Array<mixed>.
That means if you want to use it as object, your method will not work. Assuming your "object of objects" is typed as
type DataObjects = {
[string]: DataObject,
}
You'd likely be better off doing
function values(objs: DataObjects): Array<DataObject> {
return Object.keys(objs).map(key => objs[key]);
}
If you prefer to use Object.values() (probably more efficient) and have typing right, you can use a helper function like this:
function objectToValues<A, B>(obj:{[key: A]: B} ): Array<B> {
return ((Object.values(obj): any): Array<B>)
}

Function with dynamic return in typescript

I am trying to create an API on NodeJS with typescript
I have the following interfaces :
export interface ISqlResonse<T> {
success?: string
error?: string
data: Array<T> //Nothing | array of object when are db operations
}
export interface IApiResponse<T> {
status: 'error' | 'success'
message: string
data: Array<T>
}
Each api call call a function that call an generic class name DB that select/insert/update/delate data from an database
For example the update function look like :
async updateData(input: IUpdateParam) : Promise<ISqlResonse<object>> {
...
...
}
API function call DB and look like :
async update(req): Promise<IApiResponse<IAccessPointsTableStructure>> {
let data = req.body ;
let updateObj = {
data ,
table: 'accessPoints',
excludeColumns: 'loggedUserId',
additionalColumns: { modifiedBy: '1', modifiedAt: crtDate },
validationRules,
where: `id=${data.id}`,
returningData: true
}
let sqlResults = await db.updateData(updateObj) ; // !!!
if(typeof sqlResults.error==="string") {
logger.log('error','Error on updating Access Points!',{sql: db.getQuery(), error: sqlResults.error});
return({status:'error',message: 'Error on updating Access Points!',data: sqlResults.data});
}
logger.log('success', 'Access Points data updated with success!');
return({status: 'error', message: 'Access Points data updated with success!', data: sqlResults.data})
}
My question is : how can I call the function db.updateData() and tell this function that I want to receive in data from ISqlResponse an array with objects like interface IAccessPointsTableStructure.
With other words i want to control the returning type of function. I teste several times with different approaches . (Replace wit in db.updateData(...) <..>...
Thank you in advice.
You haven't included the definition of IUpdateParam, but I will assume that its table property is what decides the type of thing updateData() returns. Everywhere I've commented "guess" is just for example; you should change them to fit your use cases.
You should be able to modify the signature for the updateData() to reflect the relationship between the type of IUpdateParam passed in and the type of Promise<ISqlResponse<{}>> returned. Here's one way to do it, using generics (you could use overloads instead). First, declare a type to represent the mapping between the table names and the data type for each table. For example:
export type TableNameToTypeMapping = {
accessPoints: IAccessPointsTableStructure,
otherThings: IOtherThingsTableStructure, // guess
// ...
}
Now, you can change the definition of IUpdateParam so that it only accepts the right values for table:
export interface IUpdateParam<K extends keyof TableNameToTypeMapping> {
data: any, // guess
table: K,
excludeColumns: string, // guess
additionalColumns: any, // guess
validationRules: any, // guess
where: string // guess
}
So an IUpdateParam<'accessPoints'> object is meant to deal with the accessPoints table, and it is different from an IUpdateParam<'otherThings'> object.
Now the signature for updateData() can be changed to:
async updateData<K extends keyof TableNameToTypeMapping>(
input: IUpdateParam<K>
): Promise<ISqlResonse<TableNameToTypeMapping[K]>> {
// implement this! The implementation is likely not
// type-safe unless you use runtime type guards
}
This means if you call updateData with a parameter of type IUpdateParam<'accessPoints'>, you will get back a Promise<ISqlResponse<TableNameToTypeMapping['accessPoints']>>. But TableNameToTypeMapping['accessPoints'] is just IAccessPointsTableStructure, so you are getting back a Promise<ISqlResponse<IAccessPointsTableStructure>> as desired.
Note that the object literal updateObj will have its table property inferred as type string, which is too wide. To make sure the call to updateData() works as desired, you will either need to assert that the updateObj.table property is of literal type 'accessPoints', like this:
let updateObj = {
data,
table: 'accessPoints' as 'accessPoints', // assertion
excludeColumns: 'loggedUserId',
additionalColumns: { modifiedBy: '1', modifiedAt: crtDate },
validationRules,
where: `id=${data.id}`,
returningData: true
}
or you will need to declare that updateObj is of type IUpdateParam<'accessPoints'>, like this:
// type declaration
let updateObj:IUpdateParam<'accessPoints'> = {
data ,
table: 'accessPoints',
excludeColumns: 'loggedUserId',
additionalColumns: { modifiedBy: '1', modifiedAt: crtDate },
validationRules,
where: `id=${data.id}`,
returningData: true
}
Either way should work.
Hope that helps; good luck!

es6 syntax for factory

Could someone please explain how the following es6 code is a factory.
const createChat = ({
id = 0,
msg = '',
user = 'Anonymous',
timeStamp = 1472322852680
} = {}) => ({
id, msg, user, timeStamp
});
All the values you see (0, '', Anonymous, 1472322852680) are the default values. They would normally be extracted from the passed in object but if they don't exist these are what will be used in their place. This is default parameters.
The => ({...}) is shorthand to return the value (notice there is no return statement). So here it is returning an object with the passed in id, msg, user, and timeStamp unless those values aren't passed in. It is accomplishing this by using destructing.
https://jsfiddle.net/y7mb6jsp/

Categories

Resources