13

I copied the following from the AWS Amplify tutorial:

const styles = {
  container: { flexDirection: 'column' },
  ...
};

<div style={styles.container}>

But I'm getting:

Type '{ flexDirection: string; }' is not assignable to type 'CSSProperties'.
  Types of property 'flexDirection' are incompatible.
    Type 'string' is not assignable to type '"column" | "inherit" | "-moz-initial" | "initial" | "revert" | "unset" | "column-reverse" | "row" | "row-reverse" | undefined'.

I can easily work around this by placing the style inline, but I'm curious why TypeScript is considering this an error. This is a pretty basic example and I'm surprised TS is failing on it, so it makes me wary about using TS.

Leo Jiang
  • 24,497
  • 49
  • 154
  • 284
  • if it's angular then this sould be the syntax `
    `
    – Harkal Jun 17 '20 at 15:45
  • It's React, adding to question – Leo Jiang Jun 17 '20 at 15:47
  • the real property is `flex-direction: column` please check – Harkal Jun 17 '20 at 15:48
  • Does this answer your question? [Typescript Type 'string' is not assignable to type](https://stackoverflow.com/questions/37978528/typescript-type-string-is-not-assignable-to-type) – Charlie Bamford Jun 17 '20 at 15:49
  • @CharlesBamford no because the author in that question explicitly casted a literal to `string`. In my cast, TS is inferring the type of `styles.container.flexDirection` to be `string` rather than the literal `'column'`. I don't know why it's not treating it as a literal – Leo Jiang Jun 17 '20 at 15:57
  • try using the ```React.CSSProperties``` – pachonjcl Jun 17 '20 at 16:03

4 Answers4

18

Here is a TS Playground illustrating the problem and four possible solutions:

type FlexDirection = "column" | "inherit" | "-moz-initial" | "initial" | "revert" | "unset" | "column-reverse" | "row" | "row-reverse" | undefined;

type Styles = {
    container: {
        flexDirection: FlexDirection
    }
}

function doStuff(a: Styles) { }

const stylesDoesNotWork = {
    container: { flexDirection: 'column' }
};

const stylesWithCast = {
  container: { flexDirection: 'column' as 'column' }
}

const stylesFieldConst = {
    container: { flexDirection: 'column' } as const
};

const stylesConst = {
    container: { flexDirection: 'column' }
} as const;

doStuff(stylesDoesNotWork);
doStuff(stylesWithCast);
doStuff(stylesFieldConst);
doStuff(stylesConst);

By default, TypeScript is going to infer a type string for the object you are declaring. You might be mutating it somewhere and changing the value, in which case the literal type would not be correct. So the basic options to fix it are to:

  • Manually annotate the variable so TypeScript doesn't infer string.
  • Add as 'column' cast to tell TypeScript to use the literal type.
  • Use as const on either the field or entire object to tell TypeScript that field is not allowed to be changed, which allows Typescript to infer the literal value.
TLadd
  • 6,488
  • 2
  • 32
  • 40
  • 1
    > You might be mutating it somewhere and changing the value, in which case the literal type would not be correct. This makes perfect sense now, thanks! – Leo Jiang Jun 17 '20 at 16:17
  • if you are mutating it somewhere and changing the value, wouldn't it make sense for typescript to complain at the point where it is being mutated? why complain here where the value is correct and is one of the allowed values? – gaurav5430 Oct 24 '21 at 08:28
1

Try this

const styles: { container: React.CSSProperties} = {
    container: { flexDirection: 'column' }
};
pachonjcl
  • 723
  • 4
  • 11
  • So `styles: { [key: string]: React.CSSProperties }` works too and it's shorter if there's lots of properties, but I don't get why I need to explicitly cast it – Leo Jiang Jun 17 '20 at 16:15
1

import and use the type:

import type { Property } from 'csstype'

Use Property.FlexDirection to specify the type

Ramsses
  • 11
  • 2
1

In my case putting as const on the object that was causing this problem helped to fix it.

// some function
return {
  label: {
    cursor: "pointer",
    display: "flex",
    width: "100%",
    flexDirection: "row",
  }
} as const
Islam Murtazaev
  • 1,488
  • 2
  • 17
  • 27