Skip to content

How to get type inference? #223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
vittis opened this issue Dec 29, 2023 · 9 comments
Open

How to get type inference? #223

vittis opened this issue Dec 29, 2023 · 9 comments
Labels
bug Something isn't working

Comments

@vittis
Copy link

vittis commented Dec 29, 2023

I might be missing something trivial, but here's my case:

// define schema
const roomSchema = new Schema("room", {
  id: { type: "string" },
  name: { type: "string" },
  members: { type: "string[]" },
});

// somewhere in code...
const room = await roomRepository.fetch(roomId);
if (room.members.includes(session.userId)) { // ts-error here 
    // ...
}

The error is:

Property 'includes' does not exist on type 'string | number | true | Date | EntityData | Point | (EntityData | EntityDataValue)[] | (EntityData | EntityDataValue)[]'.

That is because looks like there's no type inference. When I type "room." the properties doesn't show up. I tried creating a interface for Room and tried plugging into generics or casting but nothing worked...

I could check if room.members exists and then check if its type is array, is that what I'm supposed to do?

@guyroyse guyroyse added the bug Something isn't working label Jan 2, 2024
@MR4online
Copy link

you have to do this by yourself.

...fetch(roomId) only has the Return-Type Entity, without knowing your action model properties.

you may define a Type:

export type Room = {
id: string,
name: string,
members: string[]
};

and then use it like:

const room = <Room> await roomRepository.fetch(roomId);

@shirecoding
Copy link

Wish there was a better way? other than redefining

@arshia-gh
Copy link

This

you have to do this by yourself.

...fetch(roomId) only has the Return-Type Entity, without knowing your action model properties.

you may define a Type:

export type Room = {
id: string,
name: string,
members: string[]
};

and then use it like:

const room = <Room> await roomRepository.fetch(roomId);

I would much prefer if this was inferred from the schema when creating a repository like many other ORMs. It'd result in way fewer bugs and improve DX

@MYKEU
Copy link

MYKEU commented Feb 20, 2024

💯 - this would be very useful to have

@shirecoding
Copy link

shirecoding commented Mar 5, 2024

yea i end up having to define so many types eg. entity type, return from rest api type etc..

how can the typed repository fetch not even return the correct type? this is not even even a typescript library

@shirecoding
Copy link

This

you have to do this by yourself.
...fetch(roomId) only has the Return-Type Entity, without knowing your action model properties.
you may define a Type:

export type Room = {
id: string,
name: string,
members: string[]
};

and then use it like:

const room = <Room> await roomRepository.fetch(roomId);

I would much prefer if this was inferred from the schema when creating a repository like many other ORMs. It'd result in way fewer bugs and improve DX

this doesnt work though it needs to export type Room extends Entity else it complains there is insufficient overlap

@hanayashiki
Copy link

this is a fake ts library

@goestav
Copy link

goestav commented Oct 31, 2024

I'm currently using this to infer the types automatically, but this should be handled by the library itself imo.

/** A point on the globe. */
interface Point {
    longitude: number;
    latitude: number;
};

/** {@link SchemaDefinition} types mapped to their Typescript type. */
interface InferSchemaMapping {
    string: string;
    number: number;
    boolean: boolean;
    "string[]": string[];
    "number[]": number[];
    date: Date;
    point: Point;
    text: string;
};

/** Utility type to infer the TypeScript types from a {@link SchemaDefinition}. */
type InferSchema<T extends SchemaDefinition> = {
    [Key in keyof T]: T[Key]["type"] extends keyof InferSchemaMapping ? InferSchemaMapping[T[Key]["type"]] : unknown;
};

(See TS playground for demo)

@timomeh
Copy link

timomeh commented Nov 10, 2024

If you have a flat object (i.e. your schema's keys exactly match your object) you can just type the schema itself:

type Room = {
  id: string
  name: string
  members: string[]
}

const roomSchema = new Schema<Room>('room', {
  id: { type: 'string' },
  name: { type: 'string' },
  members: { type: 'string[]' },
})
const roomRepository = new Repository(roomSchema, client)

const room = await roomRepository.fetch(id)
//     ^-- `room` is typed as `Room`

That won't work if you have nested JSON and use JSONPath. In this case, you can type the repository.

type Room = {
  id: string
  name: string
  members: string[]
}

const roomRepository = new Repository<Room>(roomSchema, client)

const room = await roomRepository.fetch(id)
//     ^-- `room` is typed as `Room`

This way you don't always have to write type assertions all the time. You probably don't even need to manually define those types again: in most cases, you already have those types defined in your codebase, e.g. as return types of API calls.

I'd guess that inferring it purely from the schema has some difficult edge cases, like nested JSON and JSONPath.

Keep in mind that repository.fetch() will still return an empty entity even it the entity doesn't exist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants