Thank you @Jolg42 for addressing the previous two JSON issues:
This issue is the last (I think) for end-to-end JSON typing to work.
Bug description
We get a TypeScript error during a create or update for valid JSON in a JSON column if it contains optional properties like this.
type UserJSON = {
name: string
age?: number
}
The reason this happens is because TypeScript transforms the value of the age property by adding undefined so that it becomes number | undefined. The preceding type and the following type are identical:
type UserJSON = {
name: string
age?: number | undefined
}
This is a known limitation of TypeScript. It cannot distinguish a missing property from a property which can be set to undefined. microsoft/TypeScript#13195
How to reproduce
- Create any prisma model with a JSON column
- Do a
create or update to the JSON column with a valid JSON object that has an optional property
This code clarifies why this happens:
// JSON values from `type-fest` as used in Prisma
export type JsonObject = {[Key in string]?: JsonValue};
export interface JsonArray extends Array<JsonValue> {}
export type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
type User = {
name: string,
age?: number
}
type IsUserJSON = User extends JsonObject ? true : false
// false but should be true
Expected behavior
The way to fix it is to define a UJsonValue like this and use that to type JSON values in a create or update:
// JSON values with `undefined` allowed
export type UJsonObject = { [Key in string]?: UJsonValue }
export interface UJsonArray extends Array<UJsonValue> {}
export type UJsonValue =
| undefined
| string
| number
| boolean
| null
| UJsonObject
| UJsonArray
type User = {
name: string
age?: number
}
type IsUserUJSON = User extends UJsonObject ? true : false
// true
The most accurate and strictest way to type this is to have the find methods return a JsonValue and the create and update methods to accept a UJsonValue.
This works because JSON data coming out of Prisma is guaranteed to be in the restrictive JsonValue type. It never contains undefined.
In an end to end API, that value comes out of the database will then be typed into something like User.
The end user makes a change and saves it to Prisma. The JSON data coming into Prisma should accept UJsonValue. If it is typed to accept JsonValue, we get a TypeScript error even though User is valid JSON.
The less accurate method is to add undefined to JsonValue and be done with it; however, this affects users that are strictly typing their API against JsonValue as typed in type-fest. It won't affect me and I think most users because if it flows through an API, that API has to accept undefined or else it breaks whenever there is an optional property (ie. same problem in a different place).
In order of desirability, it goes like this:
JsonValue for find and UJsonValue for create and update (Fixes all cases)
JsonValue extended with undefined (solves all my use cases and probably most people)
JsonValue as it is (breaks valid JSON with optional properties on create and update)
## Prisma information
Beta 2.0.0-beta7
Environment & setup
- OS: Mac OS
- Database: PostgreSQL
- Prisma version: 2.0.0-beta7
- Node.js version: 12.16.2
Thank you @Jolg42 for addressing the previous two JSON issues:
string. prisma#2619 (comment)This issue is the last (I think) for end-to-end JSON typing to work.
Bug description
We get a TypeScript error during a
createorupdatefor valid JSON in a JSON column if it contains optional properties like this.The reason this happens is because TypeScript transforms the value of the
ageproperty by addingundefinedso that it becomesnumber | undefined. The preceding type and the following type are identical:This is a known limitation of TypeScript. It cannot distinguish a missing property from a property which can be set to
undefined. microsoft/TypeScript#13195How to reproduce
createorupdateto the JSON column with a valid JSON object that has an optional propertyThis code clarifies why this happens:
Expected behavior
The way to fix it is to define a
UJsonValuelike this and use that to type JSON values in acreateorupdate:The most accurate and strictest way to type this is to have the
findmethods return aJsonValueand thecreateandupdatemethods to accept aUJsonValue.This works because JSON data coming out of Prisma is guaranteed to be in the restrictive
JsonValuetype. It never containsundefined.In an end to end API, that value comes out of the database will then be typed into something like
User.The end user makes a change and saves it to Prisma. The JSON data coming into Prisma should accept
UJsonValue. If it is typed to acceptJsonValue, we get a TypeScript error even thoughUseris valid JSON.The less accurate method is to add
undefinedtoJsonValueand be done with it; however, this affects users that are strictly typing their API against JsonValue as typed intype-fest. It won't affect me and I think most users because if it flows through an API, that API has to acceptundefinedor else it breaks whenever there is an optional property (ie. same problem in a different place).In order of desirability, it goes like this:
JsonValueforfindandUJsonValueforcreateandupdate(Fixes all cases)JsonValueextended withundefined(solves all my use cases and probably most people)JsonValueas it is (breaks valid JSON with optional properties oncreateandupdate)## Prisma information
Beta 2.0.0-beta7
Environment & setup