[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [Type](https://evolu.dev/docs/api-reference/common/Type) › identifier

```ts
function identifier<Casing>(
  casing: Casing,
): BrandFactory<
  IdentifierBrandByCasing[Casing],
  string,
  IdentifierError<Casing>
>;
```

Defined in: [packages/common/src/Type.ts:5694](https://github.com/evoluhq/evolu/blob/dd96d79f1dbe9a49fa12ce8e0aa7d3d0177795ca/packages/common/src/Type.ts#L5694)

Adds identifier validation in a naming convention to an existing string Type.

An identifier is one or more ASCII words, each starting with a letter and
continuing with letters or digits. camelCase and PascalCase start every word
after the first with an uppercase letter, so `httpUrl` has two words and
`httpURL` has four. snake_case, kebab-case, and CONSTANT_CASE put exactly one
separator between words. Validation keeps the spelling and rejects empty
strings, whitespace, punctuation, and non-ASCII characters.

Words never start with a digit. Identifier grammars in most languages forbid
a leading digit, and camelCase cannot mark a word boundary before one, so the
rule applies to every word and keeps every conversion exact. Join an
abbreviation such as `2FA` to the previous word, as in `MAX2FA_ATTEMPTS` and
`max2faAttempts`, or spell the number out, as in `TWO_FACTOR_SECRET`.

Convert validated identifiers with functions such as
[camelCaseToSnakeCase](https://evolu.dev/docs/api-reference/common/Type/functions/camelCaseToSnakeCase). Conversions preserve word boundaries, and
converting back restores the original spelling. They return only the
destination brand, dropping unrelated constraints such as input length.

### Example

```ts
import {
  assertErr,
  assertOk,
  identifier,
  maxLength,
  String,
} from "@evolu/common";

const EnvName = identifier("CONSTANT_CASE")(maxLength(16)(String));

assertOk(EnvName.fromUnknown("HTTP2_PORT"), "HTTP2_PORT");
assertErr(EnvName.fromUnknown("HTTP_2_PORT"));
```