I have a project in Node JS with Typescript in which I am creating an API to get data from a local JSON file depending on the given variable.
This is my model.ts
:
interface ListProductBatchModel {
resp: ResultMsg
}
interface ResultMsg {
name?: string,
price?: string,
error?: string
}
export { ListProductBatchModel, ResultMsg };
This is my properties
JSON file:
{
"CT": {
"name": "box",
"price": "5,00"
},
"CC": {
"name": "car",
"price": "6,00"
}
}
This is my controller.ts
:
import * as logger from 'winston';
import { Controller, Get, Response, Route, SuccessResponse, Tags } from 'tsoa';
import { ListProductBatchModel } from './models/listProduct.models';
import { ListProductBatchUtils } from './utils/listProductBatch.utils';
@Route('/list/product')
@Tags('list-product')
export class ListProductBatchController {
private listProductBatchUtils: ListProductBatchUtils;
constructor() {
this.listProductBatchUtils = new ListProductBatchUtils();
}
@Get('/{codProduct}')
@SuccessResponse(200, 'Success Response')
async listProductBatch(codProduct: string): Promise<ListProductBatchModel> {
try {
const listProductBatch = await this.listProductBatchUtils.getDataProduct(codProduct);
return Promise.resolve(listProductBatch as ListProductBatchModel);
} catch (error) {
logger.info(JSON.stringify(error));
return Promise.reject(error);
}
}
}
This is my utils.ts
:
import * as logger from 'winston';
import * as getProperty from '../json/product.json';
import { ListProductBatchModel, ResultMsg } from '../models/listProduct.models';
export class ListProductBatchUtils {
public async getDataProduct(codProduct: string): Promise<ListProductBatchModel> {
try {
let result: ResultMsg;
if (getProperty[codProduct.toUpperCase()]) {
result = {
name: getProperty[codProduct.toUpperCase()].name,
price: getProperty[codProduct.toUpperCase()].price
}
}else {
result = {
error: "ERROR"
}
}
logger.info('start')
return Promise.resolve({ resp: result });
} catch (error) {
logger.info(JSON.stringify(error));
return Promise.reject(error);
}
}
}
This is the error I get in getProperty [codProduct.toUpperCase ()]
:
The element has a type "any" implicitly because the expression of type "string" cannot be used to index the type "{CT: {name: string; price: string;}; CC: {name: string; price : string;};} ".
No index signature was found with a parameter of type "string" in type "{CT: {name: string; price: string;}; CC: {name: string; price: string;};}".
My problem: I don't understand how the error is generated, what I want is to take the name and price properties that match the codProduct variable. Why can this happen? What am I doing wrong and how can I solve it?
CodePudding user response:
Right now, codProduct
is a string
. When you're accessing getProduct
via its subscript []
, TypeScript expects you to use an index of getProduct
(which, in this case is either "CT"
or "CC"
).
You can satisfy the TypeScript compiler by casting your string
as a keyof
getProperty
's type. Note that this will work at compile time, but will not guarantee that it is in fact a key of getProperty
at runtime. But, since you're doing boolean checks already, that seems like it will be okay in your case.
Here's a simplified example:
const getProperty = {
"CT": {
"name": "box",
"price": "5,00"
},
"CC": {
"name": "car",
"price": "6,00"
}
};
type GetPropertyType = typeof getProperty;
function myFunc(input: string) {
const result = getProperty[input.toUpperCase() as keyof GetPropertyType].name;
}