SolvedDefinitelyTyped [@types/styled-components] How do you use attrs?

@Igorbek @probablyup originally posted this in styled-components/styled-components#1959 and was told to post here.

Hi, it's unclear how attrs should be used with TypeScript, I'm not sure if there's just a bug in the types. Here's what we've got so far, this is the only way to make the component definition work as expected, but then the component usage fails with the error [ts] Type 'string' is not assignable to type 'never'..

import styled from '../utils/mural-styled-components';

interface AdditionalProps {
  readonly size: string;
}

interface ChangedProps {
  readonly type: string;
  readonly margin: string;
  readonly padding: string;
}

const WeirdComponent = styled.input.attrs<AdditionalProps, ChangedProps>({
  // we can define static props
  type: 'password',

  // or we can define dynamic ones
  margin: (props) => props.size || '1em',
  padding: (props) => props.size || '1em',
})`
  color: palevioletred;
  font-size: 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;

  /* here we use the dynamically computed props */
  margin: ${(props) => props.margin};
  padding: ${(props) => props.padding};
`;

import React from 'react';
export const X = () => (
  <WeirdComponent size="massive"/>
); // [ts] Type 'string' is not assignable to type 'never'.

Environment

## System:
 - OS: Linux 4.15 Linux Mint 19 (Tara)
 - CPU: x64 Intel(R) Core(TM) i5-4460  CPU @ 3.20GHz
 - Memory: 7.84 GB / 15.60 GB
 - Container: Yes
 - Shell: 4.4.19 - /bin/bash
## Binaries:
 - Node: 10.7.0 - ~/.nvm/versions/node/v10.7.0/bin/node
 - npm: 6.4.0 - ~/github/mural/node_modules/.bin/npm
## npmPackages:
 - styled-components: ^3.3.0 => 3.4.4
16 Answers

✔️Accepted Answer

The answer everybody was looking for:

  import styled from 'styled-components'
  
  const Container = styled.div.attrs<
      { size: number }, // What is consumed by .attrs()
      { width: number, height: number } // What comes out of .attrs()
  >((props) => {
      return {
          width: props.size,
          height: props.size,
      }
  })<{ size: number }> // The outer type
  `
      width: ${props => props.width}px;
      height: ${props => props.width}px;
`

const container = <Container size={200} />

Other Answers:

@nielskrijger

I solved it temporarily.

import styled from 'styled-components';
import React from 'react';

interface AdditionalProps2 {
  size22: string;
  // size: string; // not works if this line uncommented.
}

const WeirdComponent = styled.input.attrs<AdditionalProps2>({})<AdditionalProps2>`
  color: palevioletred;
  font-size: 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

export const X = () => <WeirdComponent size22={'massive'} size={324} defaultValue="dsdsd" />;

Seems like size property is conflicting with React InputHTMLAttributes<T>

    interface InputHTMLAttributes<T> extends HTMLAttributes<T> {
        ...
        pattern?: string;
        placeholder?: string;
        readOnly?: boolean;
        required?: boolean;
        size?: number; //already defined
        src?: string;
        step?: number | string;
       ...
    }

And attrs calculates its attributes using diff between additional props & react element attributes.

export interface ThemedStyledFunction<P, T, O = P> {
  (
    strings: TemplateStringsArray,
    ...interpolations: Interpolation<ThemedStyledProps<P, T>>[]
  ): StyledComponentClass<P, T, O>
  <U>(
    strings: TemplateStringsArray,
    ...interpolations: Interpolation<ThemedStyledProps<P & U, T>>[]
  ): StyledComponentClass<P & U, T, O & U>
  attrs<U, A extends Partial<P & U> = {}>(
    attrs: Attrs<P & U, A, T>
  ): ThemedStyledFunction<DiffBetween<A, P & U>, T, DiffBetween<A, O & U>>
}

So below code works.

interface AdditionalProps2 {
  size22: string;
  // size: string; // not works if this line uncommented.
}

const WeirdComponent = styled.input.attrs<AdditionalProps2>({ })`
  color: palevioletred;
  font-size: 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

export const X = () => (
  <WeirdComponent size22={"massive"} size={324} defaultValue='dsdsd'/>
); 

Thanks for the tip. In my case, TS was able to infer the "what comes out of attrs", but the final "outer type" was the trick I needed. So I just did:

const Foo = styled.div.attrs<{ width: number }>(
  ({width}) => ({ style: ... })
)<{ width: number }>`
  ...
`;

Hey, @antoinerousseau, does this help? I wish this example had been around when I was first looking!

Using custom props with Styled Components in Typescript.

Custom props are props which are not valid HTML attributes of the element being styled.

Choose prop names which will clearly never conflict with any default attributes of the tag being used. eg. isFixed is not among the valid DIV attributes.

interface Props {
  isFixed?: boolean
}

const Box = styled.div`
  position: ${({ isFixed = false }: Props) => (isFixed ? 'fixed' : 'absolute')};
  top: 0;
`

export default () => (
  <div>
    <Box isFixed={true}>I'm a box</Box>
  </div>
)

Using custom props and html element attributes with Styled Components in Typescript.

In this case type is among the valid attributes of the button element, and isFixed is not!

I've found it useful to use separate interface statements for attrs and props.

interface Props {
  isFixed?: boolean
}

interface Attrs {
  type?: string
}

const Button = styled.button.attrs(({ type = 'button' }: Attrs) => ({
  type,
}))`
  position: ${({ isFixed = false }: Props) => (isFixed ? 'fixed' : 'absolute')};
`

export default () => (
  <div>
    <Button isFixed={true} type="submit">
      I'm a button with type "submit" instead of default type of "button"
    </Button>
  </div>
)

Related Issues:

310
DefinitelyTyped [@types/react] RefObject.current should no longer be readonly
It's not It'a intentionally left readonly to ensure correct usage even if it's not frozen ...
165
DefinitelyTyped node_modules/@types/react-native/globals.d.ts (36,15): Duplicate identifier 'FormData'.
Fixed by set compilerOptions.types manually If you know how to fix the issue make a pull request ins...
153
DefinitelyTyped @types/core-js breaks build in version 0.9.37
By adding to my compilerOptions in tsconfig.json solved this issue for me thanks @andy-ms ...
139
DefinitelyTyped [@types/webpack] 'devServer' does not exist in type 'Configuration'
I had better results after explicitly merging the types: I tried using the @types/webpack package an...
124
DefinitelyTyped Cannot find module 'csstype'
Try compilerOptions.moduleResolution: node (Edit by Orta: If you are seeing this inside DefinitelyTy...
103
DefinitelyTyped error TS2304: Cannot find name 'Set'. 815 allowedNodeEnvironmentFlags: Set<string>;
Same here with target and lib as es6 I've managed to fix this by installing @types/node@12.7.4. ...
99
DefinitelyTyped @types/nodemailer 6.2.0 & Typescript 3.5.1 Failure
@ruipaulo ah in your example port is a string and this is incorrect because it have to be number Rep...
96
DefinitelyTyped [@types/react] cannot setState with dynamic key name type-safe
This is a limitation of the compiler itself inferred types via computed property keys do not support...
95
DefinitelyTyped Implementing defaultProps with ts 2.0 strict null checks
If anyone has a good solution for types and defaultProps I'm all ears We currently do this: ...
85
DefinitelyTyped [@types/koa-router] incompatible type with koa
koa provides us with multiple types for ctx If you know how to fix the issue make a pull request ins...
72
DefinitelyTyped Error: Interface 'Response<ResBody>' incorrectly extends interface 'Response'
I added skipLibCheck: true in tsconfig.json so it worked for me. When I compile from typescript I ge...
71
DefinitelyTyped [@type/react] Generic Props lost with React memo
Unless you need all the baggage maybe just override the typings locally: For some reason React.memo ...
59
DefinitelyTyped TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>'
Man I solved try using --files after ts-node script: ts-node-dev --files When trying to extend the R...
58
DefinitelyTyped react-redux's connect cannot be used as a decorator: type "is not assignable to type 'void'"
To use @connectdirectly (so without introducing custom decorators) I use the following workaround: B...
57
DefinitelyTyped [@types/express] Latest types throw Property 'headers', 'body', 'query' does not exist on type 'Request<any>'
I solved this issue with yarn by doing: Have nice day! If you know how to fix the issue make a pull ...
56
DefinitelyTyped Lodash All declarations of 'WeakMap' must have identical type parameters.
IMO the best workaround is to skipLibCheck: true Once fixed you can remove it. ...
55
DefinitelyTyped [@types/react-router] Type restriction for RouteProps.component creates error
The component is required to be able to receive RouteComponentProps Change your extends React.Compon...
51
DefinitelyTyped Invalid 'reference' directive syntax
Getting the same exception I want to make PR to types-2.0 branch which change commander definitions ...
47
DefinitelyTyped Aphrodite: incompatible with @types/react 15.6.0?
Adding React to the paths object in my tsconfig.json file solved the issue for me for now: ...
41
DefinitelyTyped [lodash] Type 'T' does not satisfy the constraint 'object'.
Ok so your third party probably needs to update their dependency If you know how to fix the issue ma...
40
DefinitelyTyped @types/node observable declaration conflicts with rxjs
If anyone needs an immediate fix downgrading @types/node to 10.1.2 should work (this was the last re...
40
DefinitelyTyped [@types/styled-components] Generics in functional components (and best practise for generics in general)
The generic argument for the wrapped component can be passed like <StyledFoo<FC<Props<Bar>>> .. /> t...
39
DefinitelyTyped Promise<String>.toEqual does not accept string parameter. Requires also Promise.
Until this is fixed there are several workarounds: Fix the version of the typings to 2.5.45 This wil...
34
DefinitelyTyped Babel Plugin Relay Macro TypeScript
For me had to declare the default export: Hoping this will help TypeScript developers. ...
32
DefinitelyTyped [@types/next] withRouter in TypeScript
The just-keep-quiet option: I tried using the @types/next package and had problems I tried using the...
31
DefinitelyTyped @types/jquery giving breaking solution while Gulp build
Also getting an error after upgrading to the latest jquery typings: Reverting to @types/jquery: 2.0....
31
DefinitelyTyped @types/react Make it possible to render a string from a functional component
A workaround is to return a fragment return <>0</> I tried using the @types/react package and had pr...
30
DefinitelyTyped Duplicate identifier with @types/node 10.0
I will be able to look at this tonight. If you know how to fix the issue make a pull request instead...
29
DefinitelyTyped Subsequent property declarations must have the same type...
@allada I was able to reproduce with your pinned versions using yarn (are you using yarn?) - here's ...
27
DefinitelyTyped bluebird 3.0: how to use it as overload for global Promise?
Hi guys @types/bluebird-global is now available Hey everyone! I am using bluebird as a replacement f...
27
DefinitelyTyped [@types/react-router-dom]: withRouter HoC produces compile error: "Property 'match' is missing in type '{}'."
Same issue here: Got: Can be fixed with: Bug with withRouter declaration it can't extract real props...
27
DefinitelyTyped Enzyme instance() method should be able to carry type of wrapped class
that is unnecessary boilerplate @mohsen1 all you need to do from now on is in demonstrated in test h...
27
DefinitelyTyped v14.6.3 has error in node_modules/@types/node/index.d.ts(20,1): error TS1084: Invalid 'reference' directive syntax.
This was the same issue for us and we fixed it by using a fixed version (14.6.2) of @types/node in o...
26
DefinitelyTyped Problem defining interfaces for return document with mongoose
@maicss Can you initialize your mongoose model like this? Can you let me know if that works? ...
26
DefinitelyTyped [styled-components] v4 doesn't support React Native
Fixed now that @types/styled-components@4.1.9 is published! This issue should be closable as the typ...
25
DefinitelyTyped Property 'from' does not exist on type '{}'
If you want to get around this in not a type safe way and only if you are sure you are getting the v...
25
DefinitelyTyped [@types/express]-Type 'P' is not assignable to type 'ParamsArray'
For NPM users to update your dependency on @types/express-serve-static-core without just blowing awa...
25
DefinitelyTyped Incorrect typings for session object
@wenhx here is how I did it First I edited tsconfig.json to include custom defined types ...
24
DefinitelyTyped @types/ramda - Typings do not work for pipe function using R.filter
This is also a big problem for us I tried using the @types/ramda package and had problems I tried us...
24
DefinitelyTyped Cannot find namespace 'moment'
Hi everybody Iam new in using Typescript and angular ...
23
DefinitelyTyped Problem defining interfaces for subdocuments with mongoose
@camilleblanc Here are some alternatives you can try: Cast to any Use mongoose.Types.Array instead o...
22
DefinitelyTyped Error: node_modules/@types/jasmine/index.d.ts(138,47): error TS1005: ';' expected.
As a side note upgrading these types to require TS 2.8+ is not a minor release If you know how to fi...
21
DefinitelyTyped redux-form Field fails compile with type error if custom props on custom component are used
@LKay this typecast is almost alien: I doubt anybody installing this typings will be able to use it ...
21
DefinitelyTyped [@types/react-native]
Remove dom from lib in the tsconfig I just install the latest updates and I got a bunch of errors ...
21
DefinitelyTyped [@types/react-redux] 'hoist-non-react-statics' has no exported member 'NonReactStatics'
I could be wrong but I think the problem is maybe more simple should be downgrading to @types/react-...
20
DefinitelyTyped global declaration of Express.Request.user collides between @types/express-jwt and @types/passport
How to type request.user now: I tried using the @types/express-jwt & @types/passport package togethe...
20
DefinitelyTyped [styled-components] Cannot use forwardRef with styled component
At the moment I didn't come up with a solution yet It looked harder than I expected ...
20
DefinitelyTyped [@types/react] useEffect(async () => ...) does not account for async
Instead of this try this: I had the same issue and it helped. If you know how to fix the issue make ...
19
DefinitelyTyped Is there a typing for package.json?
A type definition for package.json is available in type-fest If you know how to fix the issue make a...