-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Add support for Typescript to carbon/react #12222
Add support for Typescript to carbon/react #12222
Conversation
✅ Deploy Preview for carbon-components-react ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify site settings. |
✅ Deploy Preview for carbon-elements ready!
To edit notification comments on pull requests, go to your Netlify site settings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this! Here's a few baseline thoughts from my first pass through.
@@ -92,6 +92,9 @@ module.exports = { | |||
}, | |||
framework: '@storybook/react', | |||
stories, | |||
typescript: { | |||
reactDocgen: 'react-docgen', // Favor docgen from prop-types instead of TS interfaces |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to ask about this. I agree and think we should favor the docgen from prop-types for now. Maybe once things are fully converted we could evaluate using the TS interfaces instead.
/** | ||
* Specify a title for the <label> node for the Checkbox | ||
*/ | ||
title: PropTypes.string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one doesn't have a type supplied in the interface above. Is that intentional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct this is intentional. The reason is because since we are doing the spread of ...others
on the input element I have decided to have the interface extend all the native props of an HTMLInputElement
using React.InputHTMLAttributes<HTMLInputElement>
. We omit some native props that we are overriding/providing stricter types for
export interface TextDirectionContextData { | ||
direction?: TextDir; | ||
getTextDirection?: MutableRefObject<GetTextDirection | undefined>; | ||
} | ||
|
||
export const TextDirectionContext = createContext<TextDirectionContextData>({}); | ||
export const useTextDirectionContext = () => | ||
useContext<TextDirectionContextData>(TextDirectionContext); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC the change here from the original file is largely because we need to have typings for everything that is placed within the context. Is that correct? It's a big stylistic change that we'll need to make for any place we use context. Tabs in particular could be a complicated refactor. Without this change does compilation fail, or is it just a warning?
I'm not sure if initializing the context to an empty object instead of null
has any side effects. I can't immediately think of any though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this is correct, the refactor here was so that we can have all the types for the context in one place. The addition of the useTextDirectionContext
was to provide a convenience method for the useContext
so we didnt have to manually pass the typing to context every time. The empty object instantiation here is from a pattern we use over in fusion-ui, since this context isnt really used too widely I was able to replace the null here with just an empty object. For other contexts that have wider usages, we can probably just incorporate null
as a valid type for the contexts to prevent bigger refactors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to go more conservatively here, we could "not" do types for the context and then just use any
here (or something similar).
If the goal is to provide types externally for carbon/react
, then this conversion of the context doesn't actually help that goal (I'm assuming this context isn't exposed externally).
I know it's tempting to type everything that's encountered along the way, but that's likely not in the best interest of the Carbon System Squad right now until the team gets more comfortable developing in typescript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A type is required for the useContext
otherwise when its used we get an object with an any
type and have no idea what properties are valid for this context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely get that, and in a totally typescript product I'd 100% agree this is the correct approach, but that's unfortunately not the state of carbon/react
...yet!
My argument is that the lack of typing on that context is no worse than what is currently present in the JS codebase. The existing code functions as-is without types. I definitely believe that converting all the things is a great eventual goal, but I don't believe that now is necessarily the right time for that.
In a general sense, what the System squad has the capacity to take on at this point maintenance and new-development-wise is the introduction of type interfaces at the externally-exposed component level, but not anything beyond that at this time. That's why I'm erring more on the side of caution with respect to the scope of things we convert to typescript out of the gate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im a little confused, are you suggesting that we not convert this file to TS at all or just remove the interface and change it to any
? Im not sure how the addition of the interface is going to cause confusion in the JS code, I would actually think that it helps set the expectations on what we are able to access and set. Are we concerned that a developer might not necessarily know that they have to add a prop to the interface if we wanted to add something new to a context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jdharvey-ibm Are you saying you'd rather
export interface TextDirectionContextData {
direction?: TextDir;
getTextDirection?: MutableRefObject<GetTextDirection | undefined>;
[key: string]: any;
}
So they can pass in additional unknown arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mbarrer sorry I missed your comment otherwise I would have responded sooner!
I'd recommend we don't convert any files to TS unless they are an exported component and are part of the public interface of the carbon/react
package. In this case, that would mean leaving the TextDirectionContext
file as a JS file and asserting the type of that context in places where it is used as any
or something else that's equally basic.
You're 100% correct that it's ambiguous what properties exist on the context and that it is (generally speaking) an improvement to the codebase to assign types to that context and other non-component files.
But with that said, the goal of this particular work item is to get component types to the community and to get them out there as quickly as possible. Thereby unblocking the transition to v11 and all its goodies. Making changes to any non-external-component file is useful, but it unfortunately doesn't expedite that goal.
Once we get the initial typings done, a great next step would be to start improving on these sorts of things to make the internals more bullet-proof.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great to me!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making those changes!
This PR currently has a merge conflict. Please resolve this and then re-add the |
With this merged, will the team start or like help converting component files to Typescript? |
Closes #11587
Closes #12654
Closes #12655
Closes #12656
Closes #12657
This PR adds support for compiling typescript files in the carbon/react package allowing us to begin converting components to typescript. As a proof of concept, Checkbox.js and all its imports have now been converted to typescript
Changelog
New
@babel/preset-typescript
added to rollup and storybook builds to transpile ts.js
files to the output directory@typescript-eslint/eslint-plugin
and@typescript-eslint/parser
added for linting@rollup/plugin-typescript
being used to perform typechecking on ts files.d.ts
files to the output directory, it does not handle generating.js
(usingemitDeclarationOnly: true
compiler option)Added TS extensions and
@babel/preset-typescript
to Jest configAdded
types/common.d.ts
with a newer typing forPolymorphicProps
(components that use 'as' props to control the root node. additional explaination)added
types/globals.d.ts
as a place to declare workspace globalsChanged
@types/react
and@types/prop-types
have been moved to resolutions and pinned to prevent pulling in types for react 18Testing / Reviewing
These changes can be tested and verified by running a fresh
yarn
,yarn build
andyarn storybook
. Verify that the behavior in both the Checkbox and Text stories remain unchanged