Skip to content

Commit

Permalink
Fix complex unions TS error with as prop (#730)
Browse files Browse the repository at this point in the history
* hallelujah

* that's a better spot
  • Loading branch information
hadihallak authored Aug 20, 2021
1 parent a2f2330 commit 0448169
Show file tree
Hide file tree
Showing 11 changed files with 17,301 additions and 7 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"workspaces": [
"packages/core",
"packages/react",
"packages/test",
"packages/stringify"
],
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export type CSS<
Config['themeMap'],
Config['utils'],
false
>
>

/** Returns the properties, attributes, and children expected by a component. */
export type ComponentProps<Component> = Component extends ((...args: any[]) => any) ? Parameters<Component>[0] : never
Expand Down
19 changes: 13 additions & 6 deletions packages/react/types/styled-component.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import type * as React from 'react'
import type * as Util from './util'


export type IntrinsicElementsKeys = keyof JSX.IntrinsicElements;

/** Removes index signatures from a type */
type RemoveIndex<T> = {
[ K in keyof T as string extends K ? never : number extends K ? never : K ] : T[K]
};
/** Returns a new Styled Component. */
export interface StyledComponent<
Type = 'span',
Expand All @@ -15,14 +22,14 @@ export interface StyledComponent<
TransformProps<Props, Media> & { css?: CSS }
>
> {
<As = Type>(
<C, As = Type>(
props: (
As extends ''
? { as: keyof JSX.IntrinsicElements }
? { as: IntrinsicElementsKeys }
: As extends React.ComponentType<infer P>
? Util.Assign<P, TransformProps<Props, Media> & { as: As, css?: CSS }>
: As extends keyof JSX.IntrinsicElements
? Util.Assign<JSX.IntrinsicElements[As], TransformProps<Props, Media> & { as: As, css?: CSS }>
? Util.Assign<P, TransformProps<Props, Media> & { as: As, css?: RemoveIndex<CSS> & {[k in keyof C]: k extends keyof CSS ? CSS[k]: never}}>
: As extends IntrinsicElementsKeys
? Util.Assign<JSX.IntrinsicElements[As], TransformProps<Props, Media> & { as: As, css?: RemoveIndex<CSS> & {[k in keyof C]: k extends keyof CSS ? CSS[k]: never}}>
: never
)
): React.ReactElement | null
Expand Down Expand Up @@ -98,7 +105,7 @@ export declare const $$StyledComponentMedia: unique symbol
export type $$StyledComponentMedia = typeof $$StyledComponentMedia

/** Returns a narrowed JSX element from the given tag name. */
type IntrinsicElement<TagName> = TagName extends keyof JSX.IntrinsicElements ? TagName : never
type IntrinsicElement<TagName> = TagName extends IntrinsicElementsKeys ? TagName : never

/** Returns a ForwardRef component. */
type ForwardRefExoticComponent<Type, Props> = React.ForwardRefExoticComponent<
Expand Down
25 changes: 25 additions & 0 deletions packages/test/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"plugins": ["react", "@typescript-eslint", "prettier"],
"env": {
"browser": true,
"jasmine": true,
"jest": true
},
"rules": {
"prettier/prettier": ["error", { "singleQuote": true }]
},
"settings": {
"react": {
"pragma": "React",
"version": "detect"
}
},
"parser": "@typescript-eslint/parser"
}
633 changes: 633 additions & 0 deletions packages/test/index.d.ts

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions packages/test/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import * as Stitches from '@stitches/react';
import * as React from 'react';
export const { config, styled } = Stitches.createStitches({
utils: {
/** util to do stuff */
ml: (value) => ({ marginLeft: value }),
},
theme: {
colors: {
red100: '#ff0000',
},
},
});
export const Text = styled('span', {});
const DEFAULT_TAG = 'h1';
const Heading = React.forwardRef((props, forwardedRef) => {
return (<>
{/* types here will be fast */}
<Text as={DEFAULT_TAG} onClick={(e) => { console.log(e.altKey); }} ref={forwardedRef}/>
<Text onClick={(e) => { console.log(e.altKey); }} ref={forwardedRef} css={{ backgroundColor: '$red100', backgroundClip: 'border-box' }}/>
<Text onClick={(e) => { console.log(e.altKey); }} ref={forwardedRef} css={{ backgroundColor: '$red100' }}/>
<Text as="b" onClick={(e) => { console.log(e.altKey); }} ref={forwardedRef} css={{ ...props.css, backgroundColor: '$red100', padding: 'initial' }}/>
<Text as="div" onClick={(e) => { console.log(e.altKey); }} css={{ ...props.css, backgroundColor: '$red100', background: 'red', paddingLeft: 'initial' }}/>
{/*
types here will be correct but autocompletion is going to be painfully slow when you add a new prop.
This is the only case where the autocompletion is slow
*/}
<Text as={DEFAULT_TAG} {...props} onClick={(e) => { console.log(e.altKey); }} ref={forwardedRef}/>
</>);
});
const App = () => {
// when consuming the component it should be very fast too
return <Heading css={{ backgroundColor: '$red100', padding: 'inherit' }}/>;
};
44 changes: 44 additions & 0 deletions packages/test/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as Stitches from '@stitches/react'
import * as React from 'react'

export const { config, styled } = Stitches.createStitches({
utils: {
/** util to do stuff */
ml: (value: Stitches.PropertyValue<'margin'>) => ({ marginLeft: value }),
},
theme: {
colors: {
red100: '#ff0000',
},
},
})

export type StitchesCss = Stitches.CSS<typeof config>

export const Text = styled('span', {
background: '$red100'
})


const DEFAULT_TAG = 'h1'

export type HeadingProps = React.ComponentProps<typeof DEFAULT_TAG> & { css?: StitchesCss }

const Heading = React.forwardRef<React.ElementRef<typeof DEFAULT_TAG>, HeadingProps>((props, forwardedRef) => {
return (
<>
{/* types here will be fast */}
<Text as={DEFAULT_TAG} onClick={(e) => {console.log(e.altKey)}} ref={forwardedRef} />
<Text onClick={(e) => {console.log(e.altKey)}} ref={forwardedRef} css={{backgroundColor: '$red100', backgroundClip: 'border-box', ml: 'auto'}}/>
<Text onClick={(e) => {console.log(e.altKey)}} ref={forwardedRef} css={{ backgroundColor: '$red100'}} />
<Text as="b" onClick={(e) => {console.log(e.altKey)}} ref={forwardedRef} css={{ ...props.css, backgroundColor: '$red100', padding: 'initial' }} />
<Text as="div" onClick={(e) => {console.log(e.altKey)}} css={{ ...props.css, backgroundColor: '$red100', background: 'red', paddingLeft: 'initial'}} />
<Text as={DEFAULT_TAG} {...props} onClick={(e) => {console.log(e.altKey)}} ref={forwardedRef} />
</>
)
})

const App = () => {
// when consuming the component it should be very fast too
return <Heading css={{ backgroundColor: '$red100', padding: 'inherit'}} />
}
27 changes: 27 additions & 0 deletions packages/test/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "@stitches/test",
"version": "1.0.0-canary.7",
"type": "module",
"files": [
"dist/*.cjs",
"dist/*.js",
"dist/*.map",
"dist/*.mjs",
"types/*.d.ts"
],
"devDependencies": {
"@stitches/react": "^1.0.0-canary.10",
"@typescript-eslint/eslint-plugin": "^1.6.0",
"@typescript-eslint/parser": "^1.6.0",
"eslint-config-prettier": "^4.1.0",
"eslint-config-react": "^1.1.7",
"eslint-plugin-prettier": "^3.0.1",
"prettier": "^1.16.4",
"typescript": "^4.3.5",
"react": "17.0.2"
},
"private": true,
"dependencies": {
"@radix-ui/react-polymorphic": "0.0.13"
}
}
Loading

0 comments on commit 0448169

Please sign in to comment.