-
-
Notifications
You must be signed in to change notification settings - Fork 503
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
Either.stringifyJSON
parameter is too wide
#1397
Comments
Thanks @OliverJAsh
I can't change the type because would be a breaking change, we can consider this change for v3.0.0 though. This is actually a bug: pipe(
E.stringifyJSON(undefined, () => ''),
E.map((s) => s.trim()) // throws Cannot read property 'trim' of undefined
) I didn't expect that alas its signature doesn't account for this case so I didn't notice the issue when implementing /**
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
* @param value A JavaScript value, usually an object or array, to be converted.
* @param replacer A function that transforms the results.
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
*/
stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
/**
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
* @param value A JavaScript value, usually an object or array, to be converted.
* @param replacer An array of strings and numbers that acts as an approved list for selecting the object properties that will be stringified.
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
*/
stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string; Any ideas how to fix this? |
another option is adding a new |
There's no way to fix it other than wrapping |
what about export const stringifyJSON = <E>(u: unknown, onError: (reason: unknown) => E): Either<E, string> =>
tryCatch(() => {
const s = JSON.stringify(u)
if (typeof s !== 'string') {
throw new Error('undefined, Functions, and Symbols are not valid JSON values')
}
return s
}, onError) |
Is that a temporary solution until we can narrow the parameter type from |
@OliverJAsh yeah, I would like to fix the existing bug asap. As a long term solution I would add a new |
@OliverJAsh I'm concerned about the usability of such an API: import { Either } from 'fp-ts/Either'
type Json = boolean | number | string | null | JsonArray | JsonRecord
interface JsonRecord {
readonly [key: string]: Json
}
interface JsonArray extends ReadonlyArray<Json> {}
declare const stringify: (json: Json) => Either<unknown, string>
interface Person {
readonly name: string
readonly age: number
}
declare const person: Person
declare const persons: ReadonlyArray<Person>
stringify(person) // doesn't compile: Index signature is missing in type 'Person'
stringify(persons) // doesn't compile |
That's because of a TS limitation with If you switch type Person = {
readonly name: string;
readonly age: number;
} If you want to use interface Person {
+ readonly [key: string]: string | number;
readonly name: string;
readonly age: number;
} IIUC, the reason TS does not infer an index signature for |
@OliverJAsh TIL, thanks for the link. We can't force users to use
Probably. But I'm not sure we can assume this, if intentional this is valid use case ( console.log(JSON.stringify({ a: 'a', b: undefined })) // => '{"a":"a"}' |
I feel like it's acceptable to ask users who really want to use Another workaround: stringify({ ...person }); It's a trade off.
You could still narrow the parameter type from import { Either } from 'fp-ts/Either';
type Json = boolean | number | string | null | JsonArray | JsonRecord;
interface JsonRecord {
readonly [key: string]: Json;
}
interface JsonArray extends ReadonlyArray<Json> {}
type JsonInput = Json | { [key: string]: JsonInput | undefined };
declare const stringify: (json: JsonInput) => Either<unknown, string>;
console.log(stringify({ a: 'a', b: undefined })); // => '{"a":"a"}'
console.log(stringify({ a: 'a', b: undefined, c: () => {} })); // errors as expected ✅ |
mmhh I disagree, personally I'm not going to change my domain model just to please
Nice
A strict Also there are other valid use cases other than // a function
console.log(JSON.stringify({ a: 'a', b: () => {} })) // => '{"a":"a"}'
// a nested undefined
console.log(JSON.stringify({ a: 'a', b: { c: 'c', d: undefined } })) // => '{"a":"a","b":{"c":"c"}}' Btw I must add a type parameter in order to fix another issue (I'm using the new import * as E from 'fp-ts/Either'
import { pipe } from 'fp-ts/function'
import * as _ from 'fp-ts/Json'
// returns `Either<unknown, unknown>`, should be `Either<unknown, string>`
pipe(E.right('a'), E.chainFirst(_.stringify)) changing the signature to You could leverage the new type parameter to restrict the type of // $ExpectError
_.stringify<_.Json>({ a: undefined })
// $ExpectError
_.stringify<_.Json>({ ...{ a: undefined } }) |
Should I close this given we're not going with my original suggestion, or do you want me to leave it open to track the other discussion points? |
Let's keep this open until Here's the new |
Just my 2 cents, but as long as we rely on This is because in order to be converted JavaScript relies on the My opinion is that if we want to rely on those two functions they should be wrapped in a tryCatch, since my understanding is that the intention is already to return an Either this should not be a breaking change. |
🐛 Bug report
Current Behavior
Extracted from gcanti/io-ts-types#154 (comment)
It's easy to make mistakes such as:
or
Expected behavior
Type errors in both of the examples above since they are clearly mistakes.
Reproducible example
See above
Suggested solution(s)
Change the parameter type from
unknown
toEither.Json
.Additional context
Your environment
Which versions of fp-ts are affected by this issue? Did this work in previous versions of fp-ts?
The text was updated successfully, but these errors were encountered: