Skip to content

Commit 29ddd9d

Browse files
authored
Merge pull request #37 from dummdidumm/svelte-component-interface
Strongly Typed Svelte Component Interface
2 parents 27b4d98 + f9b58b6 commit 29ddd9d

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

text/svelte-component-interface.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
- Start Date: 2020-09-18
2+
- RFC PR:
3+
- Svelte Issue:
4+
5+
# Strongly Typed Svelte Component Interface
6+
7+
## Summary
8+
9+
Provide a Svelte component type definition which library authors can use to provide a strongly typed Svelte component which the language server understands. Inside a `.d.ts` file:
10+
11+
```ts
12+
import { SvelteComponent } from "svelte";
13+
14+
export class MyComponent extends SvelteComponent<{...prop definition}, {...events definition}, {...slots definition}> {}
15+
```
16+
17+
## Motivation
18+
19+
Currently there is no official and easy way to provide type definitions. Devs who want to write type definitions for libraries which don't have those, or library authors who want to provide them, have no clear path on how to write these. It's also confusing to them that the current `SvelteComponent` definition does not work for this.
20+
21+
## Detailed design
22+
23+
### Usage would look like this:
24+
25+
Inside a `d.ts` file:
26+
27+
```ts
28+
import { SvelteComponent } from 'svelte';
29+
30+
declare module "myModule" {
31+
export class MyComponent extends SvelteComponent<
32+
{ propA: boolean },
33+
{ someEvent: CustomEvent<string>; click: MouseEvent },
34+
{ default: { aSlot: number } }
35+
> {}
36+
}
37+
```
38+
39+
This type definition would result in this being correct usage of the component:
40+
41+
```
42+
<script>
43+
import { MyComponent } from "myModule";
44+
</script>
45+
46+
<MyComponent propA={true} on:someEvent={e => e.detail.toUpperCase()} let:aSlot={aNumber} />
47+
```
48+
49+
The props/events/slots are typed and other props/events/slots would throw type errors.
50+
51+
### Implementation:
52+
53+
Inside `language-tools`, we already have such a type definition which is used internally and looks like this:
54+
55+
```ts
56+
class Svelte2TsxComponent<
57+
Props extends Record<string, any> = any,
58+
Events extends Record<string, any> = any,
59+
Slots extends Record<string, any> = any
60+
> {
61+
// The following three exist for type checking capabilities only
62+
// and do not exist at runtime:
63+
$$prop_def: Props;
64+
$$events_def: Events;
65+
$$slot_def: Slots;
66+
67+
constructor(options: {
68+
// ...
69+
props?: Props & Record<string, any>; // <-- typed as Props, Record<string, any> for the $$restProps possibility
70+
});
71+
72+
$on<K extends keyof Events>(
73+
event: K,
74+
handler: (e: Events[K]) => void
75+
): () => void; // <-- typed
76+
$set(props: Partial<Props> & Record<string, any>): void; // <-- typed, Record<string, any> for the $$restProps possibility
77+
// ...
78+
}
79+
```
80+
81+
The Svelte component definition is enhanced with typings for Props, Events, Slots. Enhancing the types for `$on`/`$set` and the `props` constructor param is straightforward. The `$$prop_def`/`$$events_def`/`$$slot_def` properties exist purely for type checking: They are used by the language server to provide intellisense. For the intellisense to extract the correct types, they need to be defined on the component instance. Furthermore, `$$prop_def` is a must because we transform HTMLx to JSX/TSX for the intellisense, and for that we need to provide a property for input props (`$$prop_def`).
82+
83+
Obviously it's not ideal to have type-only-properties on the definition, but with a big enough disclaimer/comment on it, this should be okay in my opinion, especially since the `$$`-prefix is already the "internal, don't use this"-notion for other properties/methods.
84+
85+
Regarding "where to put this": This is up to discussion. Currently I think enhancing `SvelteComponentDev` (which is `SvelteComponent` on the outside) with that definition is the best option. This would not be a breaking change to the existing definition because of the `any` type by default for props/events/slots.
86+
87+
## How we teach this
88+
89+
Docs on the official site as well as in the `language-tools` docs. Using it should feel straightforward for anyone who has worked with TS / library definitions before.
90+
91+
## Drawbacks
92+
93+
The `$$prop_def`/`$$events_def`/`$$slot_def` leak.
94+
95+
## Alternatives
96+
97+
We need to provide these type definitions for a clear path forward, so the only alternatives are _where_ to put them.
98+
99+
- One would be a dedicated package. But I think this feels odd/inconsistent from a developer perspective.
100+
- Another alternative would be to provide this as part of `"svelte"`, but as its own class definition (name could be `SvelteComponentDefinition`). Feels slightly less odd/inconsistent than the first option.
101+
102+
## Unresolved questions
103+
104+
- Anything that can be fine-tuned on the proposed class type definition?
105+
- Anything that I forgot that is no longer possible/throws a type error when the types are more strict?

0 commit comments

Comments
 (0)