solid-client-js
solid-client-js copied to clipboard
WIP: open discussion on typing
This commit includes two changes I want to bring up for discussion:
- Defining the constants as raw literals makes the type system more assertive (here it goes from "string" to "http://www.w3.org/ns/solid/acp#allow" | "http://www.w3.org/ns/solid/acp#deny", which I find much more helpful
- Making a function generic without changing its return type should not be necessary, because anything that matches ThingPersisted should be accepted in the proposed form, which means the generic does not add anything.
This is just a partial refactoring I want to use as a basis for conversation, it doesn't change any behaviour.
This pull request is automatically built and testable in CodeSandbox.
To see build info of the built libraries, click here or the icon next to each commit SHA.
Latest deployment of this branch, based on commit 10881cfc24f996fa2f87d8a30048713e2614b8d8:
Sandbox | Source |
---|---|
solid-client-sandbox | Configuration |
Let's start with generic parameters.
What I see in my development environment is the following:
This illustrates that anything matching the structure of a type cannot be fed into non generic parameters.
Can you not reproduce this type Error?
Code snippet:
interface TypeX {
a: string
}
function A(
x: TypeX
): string {
return x.a;
}
function B<T extends TypeX>(
x: T
): string {
return x.a;
}
A({ a: "bla", b: "bla" });
B({ a: "bla", b: "bla" });
This looks good to me, also far easier to read than the concat + some editors will make the link actually clickable too.
I didn't actually see the change to getModes
when I reviewed — the string changes look good to me though.
Regarding the generic parameters, the behaviour you observe happens when you pass in a "plain" object, and not an explicitly typed variable. The following code snippet is valid too:
interface TypeX {
a: string;
}
function A(x: TypeX): string {
return x.a;
}
function B<T extends TypeX>(x: T): string {
return x.a;
}
const myLiteral = { a: "bla", b: "bla" };
const myTypedVar: TypeX = myLiteral;
A(myTypedVar);
B({ a: "bla", b: "bla" });
Assigning const myTypedVar: TypeX = { a: "bla", b: "bla" } ;
directly would fail though, for the same reason you're pointing out. Anything that is a supertype of TypeX
is valid as an input to function A
without generics, so I don't think we need them in this case. I think that the following also provides an interesting insight: https://effectivetypescript.com/2020/08/12/generics-golden-rule/
const myLiteral = { a: "bla", b: "bla" };
const myTypedVar: TypeX = myLiteral;
This feels like it should fail and be an error..
const myLiteral = { a: "bla", b: "bla" };
const myTypedVar: TypeX = myLiteral;
This feels like it should fail and be an error..
Well the way I see it, myLiteral
is of a supertype of TypeX
, but TypeX
would be a valid interface for myLiteral
. I don't think TS types give any guarantee about things that should not be there, they only assert about what you can expect to find in my understanding. That's why it's valid to have const myVar: TypeA & TypeB
being passed to a function that accepts TypeA
, or to another function that accepts TypeB
.
What would be an error though, is to do myTypedVar.b
. Once it's been typed as some interface, there has been information loss, and the original underlying literal becomes irrelevant. It would then take a type guard to check whether myTypedVar
does have a b
property, and type it as TypeX & {b: string}
or something.
We have the same understanding Nicolas.
The syntax I'm proposing only really absolves you from casting. You can very well write:
-
A({ a: "bla", b: "bla" } as TypeX);
-
const x = { a: "bla", b: "bla" } as TypeX;
-
const x = { a: "bla", b: "bla" }; A(x);
Whether that syntax is more desirable than having a generic type input I'm not sure yet.
EDIT:
@NSeydoux very nice article by the way and I believe this rule of thumb in the TypeScript handbook about having all generics appearing at least twice is a good authoritative argument. https://microsoft.github.io/TypeScript-New-Handbook/everything/#type-parameters-should-appear-twice
I would say yes, let's factor all the ones that don't out.
This is outdated now.