Typescript typing: function arguments go through keys of nested object - typescript-typings

interface TestObject {
person: {
firstName: string;
lastName: string;
address: {
country: string;
city: string;
street: string;
}
}
id: string;
}
const t: TestObject = {} as any;
type K<T> = T extends object ? keyof T : never;
function f<T, K1 extends K<T>>(object: T, key: K1): T[K1];
function f<T, K1 extends K<T>, K2 extends K<T[K1]>>(object: T, key1: K1, key2: K2): T[K1][K2];
function f<T, K1 extends K<T>, K2 extends K<T[K1]>, K3 extends K<T[K1][K2]>>(object: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3];
// ...
function f() {
return 1 as any;
}
const result1 = f(t, 'person', 'address');
/*
const result1: {
country: string;
city: string;
street: string;
}
*/
const result2 = f(t, 'id', '');
/*
Argument of type 'string' is not assignable to parameter of type 'never'.ts(2345)
*/
Can the same be done without "death by a thousand overloads"? If there was something like Tail<T> type alias for const tuples, i think i know how i could do it.

Related

typescript nestjs Mongoose query, find() object inside an object

In my products schema, the product information is kept in a separate object. In the code below, I am trying to fetch all the products with the trademark Apple, but the code does not work.
async getProductWithStore(productInfoDto: ProductInfoDto) {
try {
const product = await this.productModel
.find({productInfo: productInfoDto})
.populate('store')
return product;
} catch (err) {
return err;
}
}
Here is the request
productInfo.dto.ts
import { IsNotEmpty, IsOptional } from "class-validator";
export class ProductInfoDto {
#IsNotEmpty()
trademark: string;
#IsOptional()
releaseYear: string;
#IsOptional()
model: string;
#IsOptional()
size: string;
#IsOptional()
gender: string;
#IsOptional()
ram: string;
#IsOptional()
screenSize: string;
#IsOptional()
storage: string;
}
product.schema.ts
import { Document, Types } from 'mongoose';
import {Prop, Schema, SchemaFactory} from '#nestjs/mongoose';
import {Store} from '../../store/schemas/store.schema';
import { Category } from 'src/category/schemas/category.schema';
import { ProductInfoDto } from '../dto/product-info.dto';
export type ProductDocument = Product & Document;
#Schema({timestamps:true})
export class Product {
#Prop({required: true})
productName: string;
#Prop({required: true})
description: string;
#Prop({required:true})
stock: number;
#Prop({required:true, type: Types.ObjectId, ref:'Category'})
category: Category;
#Prop({required:true, type:Object})
productInfo: ProductInfoDto
#Prop({required:true})
image:string;
#Prop({required:true, type: Types.ObjectId, ref:'Store'})
store: Store;
#Prop()
sales: number;
#Prop()
rating: number;
#Prop([String])
comments: string[]
}
export const ProductSchema = SchemaFactory.createForClass(Product);
I tried a lot of things from manually typing the information into the code but none of them worked
I found the solution
I replaced the .find code with the code below
async getProductWithStore(productInfoDto: ProductInfoDto) {
try {
const product = await this.productModel
.find({'productInfo.trademark':"Apple"})
return product;
}catch(err){
return err
}
}

How to change the interface key: value: string to [{ [key: string]: string }

I have interface
IUser {
name: string;
surname: string;
cityLocation: string;
}
the value will be
const user: IUser = {
"name": "John";
"surname": "Smith";
"cityLocation": "LA";
}
I have adapter, they have method which receive
function adapter(columns: { [key: string]: string }) {...}
when I try to do:
adapter(user);
I have error:
Argument of type 'IUser' is not assignable to parameter of type '{ [key: string]: string; }'.   Index signature is missing in type 'IUser'.
How can I fix it?
(funny, but when I dont use signature IUser for object user - adapter works...)
Hope for your help. Big Thx!
As the error says, Index signature is missing in type 'IUser' so add it:
interface IUser {
name: string;
surname: string;
cityLocation: string;
[key: string]: string;
}
Playground link

Mongoose Map type incompatible with TypeScript type

I have the following interface for model schema:
import { Document } from 'mongoose';
export interface ILog {
tags: { [key: string]: string }[];
}
export interface ILogDocument extends ILog, Document {}
And there is the schema:
const logSchema = new Schema<ILogDocument>({
tags: { type: Map, of: String },
});
So i get the following type error on my schema:
TS2322: Type '{ type: MapConstructor; of: StringConstructor; }' is not assignable to type 'SchemaDefinitionProperty<{ [key: string]: string; }[]> | undefined'.
I want to use proper type defintion, I tried type: Schema.Types.Mixed and its works, but is there a better way to specify mongoose type for tags: { [key: string]: string }[] ?
{ [key: string]: string }[] is not exactly Map. You can use the Map type from TS.
import { Document, Schema } from 'mongoose';
export interface ILog {
tags: Map<string, string>;
}
export interface ILogDocument extends ILog, Document {}
const logSchema = new Schema<ILogDocument>({
tags: { type: Map, of: String }
});

NestJS Prisma - Types of property entities incompatible, missing or not assigned

I'm trying to update my Postgres database using Prisma ORM in NestJS (Microservices architecture).
The code allows users to interact with invitation requests.
But I keep getting the error:
Argument of type 'Invitation' is not assignable to parameter of type 'Invitation & { work: Work; }'. Property 'work' is missing in type 'Invitation' but required in type '{ work: Work; }'.
The Full error message looks like this:
Type '{ status: "PENDING" | "ACCEPTED" | "REJECTED"; work: undefined; id: string; workId: string; coId?: string; createdAt: Date; respondedAt?: Date; owner?: string; note?: string; }' is not assignable to type '(Without<InvitationUpdateInput, InvitationUncheckedUpdateInput> & InvitationUncheckedUpdateInput) | (Without<...> & InvitationUpdateInput)'.
Type '{ status: "PENDING" | "ACCEPTED" | "REJECTED"; work: undefined; id: string; workId: string; coId?: string; createdAt: Date; respondedAt?: Date; owner?: string; note?: string; }' is not assignable to type 'Without<InvitationUncheckedUpdateInput, InvitationUpdateInput> & InvitationUpdateInput'.
Type '{ status: "PENDING" | "ACCEPTED" | "REJECTED"; work: undefined; id: string; workId: string; coId?: string; createdAt: Date; respondedAt?: Date; owner?: string; note?: string; }' is not assignable to type 'Without<InvitationUncheckedUpdateInput, InvitationUpdateInput>'. Types of property 'workId' are incompatible. Type 'string' is not assignable to type 'never'.
How can I fix this?
Thanks in advance!
The Invitation Interface:
export default class Invitation {
id: string;
workId: string;
work: string;
co?: string;
status: RequestStatus;
createdAt: Date;
respondedAt?: Date;
owner?: string;
note?: string;
}
export enum RequestStatus {
PENDING = 'PENDING',
REJECTED = 'REJECTED',
ACCEPTED = 'ACCEPTED',
}
The prisma invitation schema:
model Invitation {
id String #id #db.Uuid
workId String #db.Uuid
work Work #relation(...)
status RequestStatus
co String #db.Uuid
owner String
note String
createdAt DateTime
respondedAt DateTime
}
The Updating mechanics in Postgres Persistence Infrastructure:
async update(invitation: Invitation): Promise<Invitation> {
const entity = await this.prismaService.invitation.update({
where: {
id: invitation.id,
},
data: {
...invitation,
status: RequestStatusEntity[invitation.status],
work: undefined,
},
include: {
work: true,
},
});
return this.toDomain(entity);
}
private toDomain(
entity: InvitationEntity & {
work: WorkEntity;
},
): Invitation {
return Object.setPrototypeOf(
{
...entity,
status: RequestStatus[entity.status],
},
Invitation.prototype,
);
}
You cannot use TypeScript enums in this case as Prisma uses string literals in the generated type.
I would suggest using Prisma's types directly instead of creating your own like this:
import { RequestStatus } from '#prisma/client'
export default class Invitation {
id: string;
workId: string;
work: string;
co?: string;
status: RequestStatus;
createdAt: Date;
respondedAt?: Date;
owner?: string;
note?: string;
}

No overload matches this call error with typescript, nodejs and mongoose

I have a service in an application that was previously working but all of a sudden I am getting this typescript error and I am unsure how to go about solving it. Please see my model file:
import mongoose from "mongoose";
import { AccessType, TicketType } from "./types";
interface TicketAttrs {
name: string;
type: TicketType;
access: AccessType;
uniqueId: string;
price: number;
quantity: number;
creator: string;
}
interface TicketDoc extends mongoose.Document {
name: string;
type: TicketType;
access: AccessType;
uniqueId: string;
price: number;
quantity: number;
creator: string;
}
interface TicketModel extends mongoose.Model<TicketDoc> {
build(attrs: TicketAttrs): TicketDoc;
}
const ticketSchema = new mongoose.Schema(
{
name: {
type: String,
},
type: {
type: String,
enum: Object.values(TicketType),
},
access: {
type: String,
enum: Object.values(AccessType),
},
price: {
type: Number,
},
uniqueId: {
type: String,
},
quantity: {
type: Number,
},
creator: {
type: String,
},
},
{
timestamps: true,
toJSON: {
transform(doc, ret) {
ret.id = ret._id;
delete ret._id;
},
},
}
);
ticketSchema.statics.build = (attrs: TicketAttrs) => {
return new Ticket(attrs);
};
const Ticket = mongoose.model<TicketDoc, TicketModel>("Ticket", ticketSchema);
export { Ticket };
I get an error on ticketSchema on this line const Ticket = mongoose.model<TicketDoc, TicketModel>("Ticket", ticketSchema);
The Error Message is:-
const ticketSchema: mongoose.Schema<mongoose.Document<any>, mongoose.Model<mongoose.Document<any>>>
No overload matches this call.
Overload 1 of 6, '(name: string, schema?: Schema<TicketDoc, TicketModel> | undefined, collection?: string | undefined, skipInit?: boolean | undefined): TicketModel', gave the following error.
Argument of type 'Schema<Document<any>, Model<Document<any>>>' is not assignable to parameter of type 'Schema<TicketDoc, TicketModel>'.
Types of property 'methods' are incompatible.
Type '{ _id?: any; __v?: number | undefined; $ignore: (path: string) => void; $isDefault: (path: string) => boolean; $isDeleted: (val?: boolean | undefined) => boolean; $isEmpty: (path: string) => boolean; ... 47 more ...; validateSync: (pathsToValidate?: string[] | undefined, options?: any) => NativeError | null; } & { ....' is not assignable to type '{ name: string; type: TicketType; access: AccessType; uniqueId: string; price: number; quantity: number; creator: string; _id?: any; __v?: number | undefined; $ignore: (path: string) => void; ... 50 more ...; validateSync: (pathsToValidate?: string[] | undefined, options?: any) => NativeError | null; } & { ...; }'.
Type '{ _id?: any; __v?: number | undefined; $ignore: (path: string) => void; $isDefault: (path: string) => boolean; $isDeleted: (val?: boolean | undefined) => boolean; $isEmpty: (path: string) => boolean; ... 47 more ...; validateSync: (pathsToValidate?: string[] |
I am also getting an error saying that there is no build function, I don't understand what broke the code and it was working without any changes.

Resources