51

I have react code

export default class MyComponent extends Component<Props,State>

The question is, do I write props like a type or an interface?

type Props = {
    isActive: Boolean,
    onClick: Function
}

or

interface Props {
    isActive: Boolean,
    onClick: Function
}

also, what is the direrence, when I am not using typescript, but classic webpack+babel setup?

Or, does it even matter much to mee?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Ivan Hanák
  • 2,214
  • 1
  • 16
  • 25

2 Answers2

38

It is 2020 now and I would favor type in almost all cases with React props (general type vs interface post is here). Common cases that can be only expressed with type aliases:

// given some props from another comp that are to be altered
type ExternalProps = { a: string; b: { c: number } };

type Props_IndexType = ExternalProps["b"]; // { c: number; }
type Props_MappedType = { [K in keyof ExternalProps]: number }; // { a: number; b: number; }
type Props_DiscriminatedUnionType = { tag: "tag1"; foo: string } | { tag: "tag2"; foo: boolean}
type Props_typeOf = { foo: string } & typeof defaultProps; // see class comp example

// conditional types - ok, this one is a bit contrived, but you get the point
type Props_ConditionalType<T> = T extends true ? { a: string } : { b: number };
const Comp = <T extends {}>(props: Props_ConditionalType<T>) =>
  <div>{"a" in props && (props as any).a}</div>
render(<Comp<true> a="foo" />, document.getElementById("root"));

Class component example for illustration (OP mentions them, but above cases also apply for Hooks):

// cannot do that with interfaces
type Props = ({ tag: "tag1"; foo: string } | { tag: "tag2"; foo: boolean }) &
  typeof defaultProps;
type State = typeof initState;

const defaultProps = { a: "A" };
const initState = { c: "C" };

class App extends React.Component<Props, State> {
  static readonly defaultProps = defaultProps;
  state = initState;

  render() { ... }
}

render(<App tag="tag1" foo="foo" />, document.getElementById("root"));

The only cases, I would consider interfaces:

  • You do declaration merging of prop types in the global scope (uncommon nowadays)
  • You want to hide type implementation details, as interfaces create a new name used in error messaged, IDE type infos etc. (docs)
ford04
  • 66,267
  • 20
  • 199
  • 171
  • 1
    Considering the following quote from [TypeScript Performance Github wiki](https://github.com/microsoft/TypeScript/wiki/Performance) -> "extending types with interfaces/extends is suggested over creating intersection types", do you still favor `type` over `interface`? – Cezar Cobuz Sep 05 '22 at 06:20
17

Interfaces are a little more powerful than the corresponding type declaration, but for a set of react props, it likely doesn't matter. You can read about the differences between types and interfaces in this question.

Since you're unlikely to be extending that interface or augmenting it elsewhere, using either is probably fine. But I would say that an interface is generally preferred for defining object types since they're a little more flexible.

CRice
  • 29,968
  • 4
  • 57
  • 70
  • 8
    this answer could be outdated. And as for the "more powerful" part, the opposite could easily be argued as well. Check out: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types#comment96004001_52682220 . There are also more discussions around the internet as for whether interfaces are really "better". – ZenVentzi Nov 14 '19 at 14:31
  • @ZenVentzi if it was outdated before, it might be preferred again: https://stackoverflow.com/questions/72598769/intersection-types-vs-interfaces-in-typescript . If the reasoning behind being "better" is to allow more flexibility when defining complex/union types, then some might see that as defeating the purpose of using TypeScript in the first place. All comes down to preference. Here's some pros for Interface: (1) define, more specifically, the shape of objects and their contracts, (2) has declaration merging, (3) can be implemented by classes, and (4) just looks syntactically prettier (imo) – Devin B. Aug 24 '23 at 23:01