Router: Revisit First-class TypeScript Support

Created on 21 Aug 2019  路  2Comments  路  Source: reach/router

Problem

The community has expressed interest in providing TypeScript support and some level of it has been provided by a 3rd party individual; however, people are still struggling with how to do simple things with this library in TypeScript.

I realize that a newer version of this library is in the works, so I'm hoping to solve this problem sooner than later.

Solution

If this library's source code were written in TypeScript and definition files generated, it would result in the following benefits:

  • Built-in editor support w/o the need to npm install @types/reach__router.
  • Generated type definitions are published with each release of @reach/router, which means whenever someone installs it, they are given 100% accurate and in-sync definitions.
  • People won't struggle when using TypeScript with this library, because it will already be designed in such a way that "the TypeScript way" is painless.
  • With proper use of generics, you can really be expressive at telling the user exactly what types they are dealing with, which props are accepted by a particular component and even add some HTML attributes for free.

This is what is meant by first-class TypeScript support.

Fears

Will it increase the footprint of this lib that we're trying to keep under 4kb?

No. You can optionally compile to an older ES5 target if you wish, but that's most likely unnecessary. Even if you do, you can use the tslib dependency along with some compiler options to prevent the compiler from emitting helpers at the top of certain files that use modern features.

If you use a relatively modern compile target, the build will be slim. There are numerous ways to optimize the build via compiler options so that you can write your code in esnext and let the compiler worry about the rest. You can reevaluate your compile target at any point of time in the future, making it even slimmer as you remove support for older browsers / environments.

Isn't TypeScript hard?

In the context of a library, it does present an additional challenge of anticipating how the user will use it and how your types are expressed in such a way that it is the most helpful. But this is totally worth it, because it helps you to make decisions that are more expected and consistent. Ultimately, you're left with a better product than you would have achieved without TypeScript.

We don't have enough resources for this!

You have me. I'm 100% willing to help in any capacity that I can. I've rewritten entire libraries in TypeScript before. You'd be surprised how tenacious I can be.

Related: #11 #21 #56 #64 #77 #129 #141 #147 #185

Most helpful comment

Some context: https://reacttraining.com/blog/reach-react-router-future/

As we design the hook based API TypeScript compatibility will much better.

Not only will we be designing APIs that typescript doesn't hate (cloneElement), we know enough typescript to write our *.d.ts files, so we'll treat it just like proptypes. With this approach is a risk they'll get out of sync but that's the tradeoff we're going to make rather than rewriting this and React Router in TS.

I think the benefit to maintainers of a library are a lot smaller than for team on an application. And as long as we ship with accurate type definitions, our consumers should get all the benefits they want.

You have me. I'm 100% willing to help in any capacity that I can.

We're working hard for a smooth migration path from the current API to the hooks-based API, let us get that settled and then we will consider taking you up on this offer :P

All 2 comments

Some context: https://reacttraining.com/blog/reach-react-router-future/

As we design the hook based API TypeScript compatibility will much better.

Not only will we be designing APIs that typescript doesn't hate (cloneElement), we know enough typescript to write our *.d.ts files, so we'll treat it just like proptypes. With this approach is a risk they'll get out of sync but that's the tradeoff we're going to make rather than rewriting this and React Router in TS.

I think the benefit to maintainers of a library are a lot smaller than for team on an application. And as long as we ship with accurate type definitions, our consumers should get all the benefits they want.

You have me. I'm 100% willing to help in any capacity that I can.

We're working hard for a smooth migration path from the current API to the hooks-based API, let us get that settled and then we will consider taking you up on this offer :P

I'm just about to do my first hello world with the router, so take my suggestion with a grain of salt. Here are two solutions off the top of my head.

1

Would it be worth changing some of the properties of the global JSX namespace when Router is added into the file?

In TS world, adding import React from 'react' allows the JSX to be converted into createElement(...), so it'd append some new properties to React.children when Reach is imported.

OR

2

Ideally, when wrapping a custom component with <Router/>, I feel we could force all the children to have props which automatically extend ReactComponentProps.

This would save having to extend your own props anytime you want to use the router (unless your using those prop values in your component, then it should be extended)

Not even sure that's possible, but seems possible.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alexluong picture alexluong  路  3Comments

benwiley4000 picture benwiley4000  路  4Comments

magnusarinell picture magnusarinell  路  3Comments

sseppola picture sseppola  路  4Comments

ssured picture ssured  路  3Comments