# Defining types

# Variants

Enums should be used when declaring variants based on a fixed set of values.

export enum Variant {
  DEFAULT = "primary",
  PRIMARY = "primary",
  SECONDARY = "secondary",
  TERTIARY = "tertiary",
}

type Props = {
  variant: Variant;
};

export declare function Button(props: Props): JSX.Element;

Here the enum constants are implementation details.

export type Variant = "primary" | "secondary" | "tertiary";

type Props = {
  variant: Variant;
};

export declare function Button(props: Props): JSX.Element;

# Type parameters

Generic type parameters should be prefixed by T and should be in PascalCase.

Good names include TName, TFunctionMap, TRootState.

Bad names include Name (not prefixed by T), and TfunctionMap (functionMap not in PascalCase).

This can be enforced using the @typescript-eslint/naming-convention ESLint rule.

{
  "rules": {
    "@typescript-eslint/naming-convention": [
      "warn",
      {
        "selector": "typeParameter",
        "format": ["PascalCase"],
        "prefix": ["T"]
      }
    ]
  }
}

naming-convention
https://typescript-eslint.io/rules/naming-convention/

# Properties with function types

# Avoid arrow function syntax

Properties with function type declarations should not use the arrow function syntax.

type Foo = {
  bar(): void;
  baz(qux: BazProps): void;
};
type Foo = {
  bar: () => void;
  baz: (qux: BazProps) => void;
};

# Function parameters

Functions that take a single object parameter (which are encouraged by this guide) should define a type for that object. That type should have the name of the function in PascalCase with pre Props suffix.

type InsertManyProps = {
  value: string;
  index: number;
  count: number;
};

function insertMany({ value, index, count }: InsertManyProps) {
  /* ... */
}
// This type has the wrong name
type InsertProps = {
  value: string;
  index: number;
  count: number;
};

function insertMany({ value, index, count }: InsertProps) {
  /* ... */
}

# Avoid inline types for destructured parameters

type InsertManyProps = {
  value: string;
  index: number;
  count: number;
};

function insertMany({ value, index, count }: InsertManyProps) {
  /* ... */
}

Functions taking more than one parameter are discouraged, but if used, inline types are allowed when they are simple enough:

function insert(value: string, index: number) {
  /* ... */
}

Simple types are primitive types, like string, number, boolean, generic types, such as Array<T> and Record<string, number>, and interfaces, classes and type aliases.

Union types, intersection types and custom object types should be used through type aliases.

function insertMany({
  value,
  index,
  count,
}: {
  value: string;
  index: number;
  count: number;
}) {
  /* ... */
}