antoniandre / wave-ui

A UI framework for Vue.js 3 (and 2) with only the bright side. ☀️
https://antoniandre.github.io/wave-ui
MIT License
544 stars 39 forks source link

[Typescript] Initial Typescript support #124

Closed DerrikMilligan closed 11 months ago

DerrikMilligan commented 11 months ago

This pull request adds initial typescript support to the project. I have never added Typescript to a project like this so I'm sure there are area's that can be improved upon but hopefully this can serve as a base for us to work from going forward as contributors to the project.

I'll try and detail all the changes I've made, why things were changed, and what work still needs to be done going forward.

Typescript

In order to parse typescript files we needed to add the typescript package to the project. This allows us to run tsc which is how we can parse and compile the various definitions in the project.

tsconfig.json

I removed the jsconfig.json file as it should be superseded by the tsconfig.json file which we now have. I'm by no means proficient with all the options in here and was just working to try and put together something that I could get working. If it needs adjusting or improvements I'd welcome it.

CompilerOptions

There are a few options under the CompilerOptions section that I needed to get this working.

This paths section just matches the alias from vite.config.js as the alias to get to the src folder. The baseUrl is used to denote where the paths start from.

{
  // ...
  "baseUrl": ".",
  "paths": {
    "@/*": [ "src/*" ]
  }
}

These three settings are what are compiling and copying the declaration files to the dist/types/ folder. I'm not 100% sure that declaration is necessary but we don't want to output any JS with this currently so it's great! The outDir is where we will output all the compiled types files. This could be moved but being part of the dist folder means we don't have to change how we bundle the NPM package as the types will be added to the dist as part of the build process.

{
  // ...
  "declaration": true,
  "outDir": "dist/types/",
}

package.json

There were just a couple small changes in here besides the added packages.

  1. The types field lets external packages know where to look for types by default. And our compilation will output this index file that re-exports all other types.
  2. I added a new command: build-types which will run tsc and build the types
  3. I modified the existing build-bundle command to also run the build-types command.

Eslint

As it stands, the eslint config is not ready to support typescript files. So I added the bare minimum configuration (as explained in their documentation here) needed.

This adds a few packages to the project:

As well as the additional plugin to the /eslintrc.cjs file. I didn't add any additional rules to tweak the plugin:@typescript-eslint/recommended rules. I figure you'll have opinions about how you'd like those to be moving forward.

Rules

It's worth noting that I was fighting a few rules and disabled them often throughout a lot of the new definition files. Namely:

Perhaps there's a better way to deal with these in the component definition files but they were enough work to get out the door as is without trying to satisfy all these rules.

Component Definitions

So I also have included in this pull request component definitions for most all of the component files (I left a few out that are not currently in use). I hacked together a script to help build the base of these files by extracting information from the actual component .vue files and from their associated documentation api.vue files. The script is here in case anyone has a need of it. But it's been put together in haste and meant to only run once. I assume we will modify the type files by hand from here on out.

As part of compiling the types I attempted to include JSDoc on everything with links back to the online wave documentation as well as all the type and param information I could extrapolate from the components.

To create the final Vue component type I'm using DefineComponent which may or may not be the most correct way to do it. The amount of examples for manually typing Vue components online was lacking severely. If someone has a better way of doing this or know how to work with DefineComponent better that'd be great! The last main hurdle I was facing was getting JSDoc to display for event handlers. But I can't get them to display when using the defineEmits in a <script setup lang="ts"> type component either. So I think it may have something to do with how the Vue Language Server handles things under the hood.

A note on slots

We have several instances where we use a slot with a dynamic name. For example on the w-select we have the item.x slot where x is replaced by a number for which item you want to actually have a custom slot for. To represent this in types and have auto completion where possible I added a slot with the actual name item.x which will show up in auto completion and get you your scoped typing. When you change it to an item.1 you will no longer get the documentation for the slot. HOWEVER I was able to get the type to recognize those as valid slot names. So it will not give an error saying the slot name is invalid. It just also won't give documentation :( Perhaps someone else is more clever than me at solving this. I tried a few various techniques including contemplating having slots for 1-10 but I didn't love that approach. I'm happy to discuss how to handle this going forward.

Usage

The components are currently in a workable state and can be used like this if you have globally registered components:

import type {
  WSelect,
  WList,
  // ...
} from 'wave-ui';

declare module '@vue/runtime-core' {
  export interface GlobalComponents {
      WSelect: WSelect,
      WList: WList,
      // ...
  }
}

And by so doing you'll get:

Props Documentation:

image

Props Autocomplete:

image

Emit Autocomplete:

image

Slot Autocomplete and Documentation:

image

Slot name type checking:

image

Scoped slot binding types (there are a lot that need updating here):

image

Method Autocomplete for template refs:

image

Additional Work Needed

As the components currently stand they're in a usable state. However they're missing several things that couldn't be inferred Here's a short list though of things that need work:

antoniandre commented 11 months ago

This is awesome @DerrikMilligan, thanks for your hard work contributing to Wave UI! 👏 I'll certainly need some time to review/integrate. I'll keep u posted

antoniandre commented 11 months ago

Hey @DerrikMilligan, I have merged in and reviewed a little. That's a solid great start! I have a couple of questions that you may be able to help me with:

I'll fill up the descriptions slowly and try to replace some anys and improve what I can.

Help is most welcome, anybody :)

DerrikMilligan commented 11 months ago

Hey @antoniandre So glad you got a chance to look at this and that you think it's a good direction! I'm happy to help fill out types to as we go, and I'm happy to help answer questions or work on it with you more as needed.

Yes! We should be able to test the autocompletions. I was primarily testing it from my editor using the LSP to make sure things where displaying when expected. But I know that at least for the DefinitelyTyped project that when having types they recommend having a <my-package>-tests.ts file that just verifies that the types exist. This isn't a file that will ever be ran, but would let us import the Component types to ensure that things look correct. So we could maybe use this to make sure that the component types have a prop that they're expected to have. Or even just to play with the completions.

I think we can have lower case file names. We can play around with that and see how it looks.

Here's a question for you though. What other work can I, or the community, do to help this be ready to merge into master? I know that it's brand new and there's lots of verifying of things that needs to be done. But maybe we could make a sort of checklist of the things you'd like done or tested so that I, or others, can pitch in!