-
Notifications
You must be signed in to change notification settings - Fork 39
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
co.json: Allow interface types from generics #470
Comments
I came across this discussion in Svelte some time ago: sveltejs/kit#1997. I can share some background info. There are many behaviour differences between interfaces and type literals in Typescript and unfortunately this is one of them. This issue is rooted in the design choice of Typescript where interfaces do not carry an implicit index signature while type literals do. See microsoft/TypeScript#15300. ^ In other words, From a DX perspective, is providing a utility along with clear instructions and examples for devs sufficient? Note: |
Thanks @milkcask!
We can give it a try, do you have any examples that we could follow? For now we are suggesting this as workaround which actually turns off our checks: export class MyCoMap extends CoMap {
data = co.json<unknown>() as co<MyInterface>
} Anything better than this is highly appreciated. |
Found the answer in the linked issue, but our use case is a little more tricky because it is a property definition. type Typify<T> = { [K in keyof T]: Typify<T[K]> };
interface ValidInterface {
prop: string;
prop2: number;
}
export class MyCoMap extends CoMap {
// This works, yay!
data = co.json<Typify<ValidInterface>>();
}
const data: ValidInterface = {
prop: "test",
prop2: 123,
};
// This doesn't validate and would need casting
MyCoMap.create({ data }, { owner: me }); |
@gdorsi Your snippet lgtm and should work. What is tsc complaining about on your end? I usually use this to avoid unnecessary recursion: type InferIndexSignature<T> = { [K in keyof T & keyof T]: T[K] }; |
@milkcask Confirm that it works! Not sure why it didn't this morning 🤔 Thanks for the suggestion and for double-checking it! |
I wonder why we can't do a conditional Generic gate like Am I missing something? |
I think the homomorphic version of Typify / InferIndexSignature can be adjusted so that it extends (or intersects) type TypifiedJsonValue<T> = { [K in keyof T & string]: T[K] extends JsonValue | undefined ? T[K] : never };
json<T extends JsonValue | TypifiedJsonValue<T>>(): co<T> { ... } It’s interesting that this works. @aeplay Yes, that should work too, but a drawback is that when an error occurs, the error elaboration stops at the bare |
Didn't know that was possible to use the generic as argument for the extend 🤯 This opens up a possible solution for us! I've made a quick draft, needs more tests but seems to work: https://github.com/gardencmp/jazz/pull/492/files |
@gdorsi That's one of the many undocumented uses of typescript and was added because Immutable.js needed it. As seen in that issue, it can be combined with recursion but there isn't a straightforward way to do it with plain interfaces & constraints (unlike ImmutableMap, where you still need to manually create an instance). So I guess your solution is sufficient for most use cases. Quite an interesting problem. |
The
co.json
type factory accepts a generic to let the Jazz users define the expected shape.We want to make it possible to pass as argument only types that can be serialized, which means that anything that includes functions shouldn't be accepted as valid type.
The current implementation doesn't accept valid interface types, leading to some confusion when trying to use
co.json
correctly.We want to fix the generic type in order to work in the following way:
The text was updated successfully, but these errors were encountered: