'iDocumentStore' only refers to a type, but is being used as a value here - lit-element

I have an interface:
export interface iDocumentStore {
hasSpaceInfo: boolean;
docId: string;
}
I get the following error when trying to do
#property({ type: iDocumentStore })
Is there a way to specify a type interface for a property?
I'm create a web component using lit element.

The type option for properties is a JavaScript type that Lit uses to convert a string attribute into a property and the property value into a string attribute at runtime. It is not not the same as TypeScript's type checking. You'll want to specify the TypeScript type as usual on the property and if the value will convert to/from JSON you can specify Object as the type for Lit to convert at runtime.
#property({ type: Object })
doc?: iDocumentStore;
Example

Related

How to define a constant in the swagger definition of a NestJS Class?

I have a bunch of Exceptions that use the same interface, so it is easier for the frontend to distinct between them from the same endpoint.
I want to be able to document in swagger that MyWeirdExpection has a property type that has the value my-weird-exception (it comes from an string ENUM if that is relevant).
Is this possible to do?
Something like:
enum MyEnum {
MyWeirdExpection: 'my-weird-exception',
RegularExpection: 'my-regular-expection'
... more
}
#ApiProperty({
description: 'Frontend can react on this property',
type: String, // <-----------WHAT HERE?
})
type: MyEnum.MyWeirdExpection;
Again, my goal is that in the swagger definition, says that MyWeirdExpection.type is the constant 'my-weird-exception'
The following will provide a type of MyEnum.MyWeirdExpection with the value populated as 'my-weird-exception':
#ApiProperty({
description: "Search by asset type",
required: false,
default: MyEnum.MyWeirdExpection,
type: MyEnum.MyWeirdExpection
})
assetType4: string | undefined;

How to get the types of a prisma model and place them in an array in Nestjs?

I have a Nestjs app using Prisma. For one given model, I want to send via controller the model attributes with its types, so that I can generate a form in the front end. What is the best way to do it?
What I have:
A prisma model and its corresponding DTO class in Nestjs:
// create-job-offer.dto.ts
import { IsOptional, IsNumber } from 'class-validator';
export class CreateJobOfferDto {
#IsNumber()
#IsOptional()
mentorId: number;
#IsNumber()
#IsOptional()
companyId: number;
}
I want to be able to send to my FE something like:
[{key: 'mentorId', type: 'number'}, {key :'companyId', type: 'number'}]
So that I can create a form, and for every input have the correct type. For example, if type is boolean, I'd generate a checkbox.
TypeScipt type is not an object. You can not treat typescript types as objects - ie can't iterate through them etc.
The standard way to share types is to use a #types package. TSLang website has a good explanation on how that works.
https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html
However, at my company, we will only use #types packages for packages that get published to npm because it takes too long to create one.
We will have a types.ts file for each module. Say, a custom-form.types.ts file, which may have the following code in it.
export interface MentorForm {
mentorId: number;
companyId: number | undefined;
mentorName: string;
...
}
And then we will share this file with the frontend development team. Because of how typescript works, you can not iterate through the keys of the interface directly. You can use a transformer to get the keys of an interface in an array.
const KeysOfMentorForm = keys<MentorForm>();
If you want to generate your forms in the front end programmatically, the easiest option would probably be to do something like this.
let mentorA : MentorForm;
let keyAndTypeArray : {key : string, type: string}[] = [];
for(let key of KeysOfMentorForm){
let type : string = (typeOf mentorA[key]).toString();
keyAndTypeArray.push({key : key, type : type})
}
Then you can iterate through the keyAndTypeArray to generate the form.

Typegoose enum arrayProp returns an error: Type is not a constructor

I have got a problem with the definition of my array schema. So basically, what I wanted to achieve is a single user Model with a property called games, that holds an array of games user is playing. The problem is I have got defined games as enum:
module Constants {
export enum Games {
LOL = 'League Of Legends',
}
}
export {Constants};
And now, when I try to attach it to the schema model like that:
#arrayProp({ required: true, items: Constants.Games })
games: Constants.Games[];
I receive an error (after a successful compilation, just before the server start)
^ const instance = new Type();
TypeError: Type is not a constructor
at baseProp (C:\Users\Borys\Desktop\lft\backend\node_modules\typegoose\lib\prop.js:114:22)
at C:\Users\Borys\Desktop\lft\backend\node_modules\typegoose\lib\prop.js:177:9
at DecorateProperty (C:\Users\Borys\Desktop\lft\backend\node_modules\reflect-metadata\Reflect.js:553:33)
at Object.decorate (C:\Users\Borys\Desktop\lft\backend\node_modules\reflect-metadata\Reflect.js:123:24)
at __decorate (C:\Users\Borys\Desktop\lft\backend\build\dataModel\User.js:4:92)
at Object.<anonymous> (C:\Users\Borys\Desktop\lft\backend\build\dataModel\User.js:64:1)
I have read a little bit about this error, but it relates to the required option for items/itemsRef I tried removing required, using enum, using even itemsRef and relating to the different set of documents but none of these worked for me.
Anyone could help/relate?
The problem is, you cannot use enums as an runtime mongoose type, so i would recommend using
#prop({ required: true, type: String, enum: Constants.Games })
games: Constants.Games[];
type for setting the type (which is string) (this option can be omitted - thanks to reflection)
enum for setting an enum to validate against
#arrayProp({ required: true, items: String })
games: Constants.Games[];
is a solution to this problem.
I would appreciate it if anyone could clarify and tell me more about why shouldn't I use enum in the items property.

How to add a `resolveType` to GraphQL?

I am trying to query a single MongoDB document (trivia) using GraphQL, but am having trouble with one of the document fields. It's the trivia.rounds field that should return an array of objects (either LightningRound or MultipleChoiceRound).
schema.graphql
type Trivia {
_id: String!
createdAt: String!
rounds: [Round]!
}
interface Round {
type: String!
theme: String!
pointValue: Int!
}
type LightningRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [LightningRoundQuestion]
}
type MultipleChoiceRound implements Round {
type: String!
theme: String!
pointValue: Int!
questions: [MultipleChoiceRoundQuestion]
}
// ...
trivia.js // resolver
require('dotenv').config()
const { ObjectId } = require('mongodb')
const trivia = (app) => {
return async (root, { _id }) => {
return app
.get('db')
.collection(process.env.DB_COLLECTION_TRIVIA)
.findOne(ObjectId(_id))
}
}
module.exports = {
trivia
}
graphql query
query {
trivia(_id: "5e827a4e1c9d4400009fea32") {
_id
createdAt
rounds {
__typename
... on MultipleChoiceRound {
type
theme
}
... on PictureRound {
type
theme
}
... on LightningRound {
type
theme
}
}
}
}
I keep getting the error:
"message": "Abstract type \"Round\" must resolve to an Object type at runtime for field \"Trivia.rounds\" with value { questions: [[Object], [Object]] }, received \"undefined\". Either the \"Round\" type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function."
I don't understand what it means by resolveType or isTypeOf. I've seen this in other questions, but have no clue what to implement in my setup. The db connection and resolver works fine if I remove the rounds field, so it's something there...
GraphQL supports two kinds of abstract types -- unions and interfaces. An abstract type is a type that represents two or more possible types. Abstract types allow you to specify a single type for your field that could be one of several possible types at runtime (i.e. when the query is executed). When executing a query, GraphQL can never return an abstract type -- instead, the type has to be resolved into one of the possible types when the query is executed.
If a field returns a list, then the type for each item in the list will resolved separately. This type resolution happens before any of the fields on each item are resolved. More to the point, the type that's resolved determines which fields need to be resolved in the first place.
In your example above, you've defined an abstract type (the interface Round) and several possible types for it (LightningRound, MultipleChoiceRound, etc.). However, you have not told GraphQL how to determine whether a Round is a LightningRound, a MultipleChoiceRound or another possible type. This is the purpose of providing a resolveType function. You typically define a resolveType function for each abstract type in your schema. Assuming you're using graphql-tools or apollo-server, you provide this function through the same resolver map object you use to define your resolvers:
const resolvers = {
Round: {
__resolveType: (round) => {
// your code here
},
},
}
resolveType will be passed the Round object (i.e. one of the objects returned by your rounds resolver) -- you can use that value to determine what kind of Round it is. Based on your code, I'm guessing you'd use the type property to differentiate between the different types. resolveType should return a string value with the name of the matched type. So it could be as simple as:
const resolvers = {
Round: {
__resolveType: (round) => {
return round.type
},
},
}
For additional examples, see the docs.
isTypeOf is an alternative approach to resolving the type. Instead of defining a resolveType function for the abstract type, you can define a isTypeOf function for each possible type. This function returns true or false to indicate whether the object it received is in fact the type. There are uses for isTypeOf, but it's typically easier to just use resolveType instead.

Using TypeScript enum with mongoose schema

I have a schema with an enum:
export interface IGameMapModel extends IGameMap, Document {}
export const gameMapSchema: Schema = new Schema({
name: { type: String, index: { unique: true }, required: true },
type: { type: String, enum: CUtility.enumToArray(GameMode) }
});
export const GameMap: Model<IGameMapModel> = model<IGameMapModel>('GameMap', gameMapSchema);
The GameMap is an enum.
First problem is already in here: I need to convert the enum to a string array in order to use it with the schema.
Secondly, I wanna use an enum value directly during the schema creation.
new GameMap({
name: 'Test',
type: GameMode.ASSAULT
});
returns ValidationError: type: '1' is not a valid enum value for path 'type'.
I am not sure whether this can actually work due to the string array I set in the model enum property.
My idea would be to create some kind of type conversion during the schema creation. Does this work with mongoose or would I have to create some kind of helper for object creation?
GameMode.ASSAULT is evaluating as it's numeric value, but GameMode is expecting the type to be a string. What are you expecting the string evaluation to be? If you need the string value of the enum, you can access it with GameMode[GameMode.ASSAULT], which would return ASSAULT as a string.
For example:
enum TEST {
test1 = 1,
test2 = 2
}
console.log(TEST[TEST.test1]);
//Prints "test1"
From the Mongoose docs on validation, in schema properties with a type of String that have enum validation, the enum that mongoose expects in an array of strings.
This means that CUtility.enumToArray(GameMode) needs to either return to you an array of the indexes as strings, or an array of the text/string values of the enum--whichever you are expecting to store in your DB.
The validation error seems to imply that 1 is not contained within the array that is being produced by CUtility.enumToArray(GameMode), or the validation is seeing GameMode.ASSAULT as a number when it is expected a string representation of 1. You might have to convert the enum value you are passing in into a string.
What is the output of CUtility.enumToArray(GameMode)? That should help you determine which of the two is your problem.
Why don't you just create custom getter/setter:
const schema = new Schema ({
enumProp: {
type: Schema.Types.String,
enum: enumKeys(EnumType),
get: (enumValue: string) => EnumType[enumValue as keyof typeof EnumType],
set: (enumValue: EnumType) => EnumType[enumValue],
},
});
EDIT:
Don't forget to explicitly enable the getter
schema.set('toJSON', { getters: true });
// and/or
schema.set('toObject', { getters: true });
This way you can fine-control how exactly you want to represent the prop in the db, backend and frontend (json response).

Resources