Skip to content

Commit

Permalink
Add ScreamingSnakeCase type (#214)
Browse files Browse the repository at this point in the history
Co-authored-by: Sindre Sorhus <[email protected]>
  • Loading branch information
Yash-Singh1 and sindresorhus authored Jun 1, 2021
1 parent 9f4817e commit ebb5a2d
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 0 deletions.
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ Click the type names for complete docs.
- [`SnakeCase`](ts41/snake-case.d.ts) – Convert a string literal to snake-case (`foo_bar`).
- [`SnakeCasedProperties`](ts41/snake-cased-properties-deep.d.ts) – Convert object properties to snake-case (`foo_bar`).
- [`SnakeCasedPropertiesDeep`](ts41/snake-cased-properties-deep.d.ts) – Convert object properties to snake-case recursively (`foo_bar`).
- [`ScreamingSnakeCase`](ts41/screaming-snake-case.d.ts) - Convert a string literal to screaming-snake-case (`FOO_BAR`).
- [`DelimiterCase`](ts41/delimiter-case.d.ts) – Convert a string literal to a custom string delimiter casing.
- [`DelimiterCasedProperties`](ts41/delimiter-cased-properties.d.ts) – Convert object properties to a custom string delimiter casing.
- [`DelimiterCasedPropertiesDeep`](ts41/delimiter-cased-properties-deep.d.ts) – Convert object properties to a custom string delimiter casing recursively.
Expand Down
23 changes: 23 additions & 0 deletions test-d/screaming-snake-case.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {ScreamingSnakeCase} from '../ts41/screaming-snake-case';
import {expectType} from 'tsd';

const screamingSnakeFromCamel: ScreamingSnakeCase<'fooBar'> = 'FOO_BAR';
expectType<'FOO_BAR'>(screamingSnakeFromCamel);

const screamingSnakeFromKebab: ScreamingSnakeCase<'foo-bar'> = 'FOO_BAR';
expectType<'FOO_BAR'>(screamingSnakeFromKebab);

const screamingSnakeFromSpace: ScreamingSnakeCase<'foo bar'> = 'FOO_BAR';
expectType<'FOO_BAR'>(screamingSnakeFromSpace);

const screamingSnakeFromSnake: ScreamingSnakeCase<'foo_bar'> = 'FOO_BAR';
expectType<'FOO_BAR'>(screamingSnakeFromSnake);

const screamingSnakeFromScreamingSnake: ScreamingSnakeCase<'FOO_BAR'> = 'FOO_BAR';
expectType<'FOO_BAR'>(screamingSnakeFromScreamingSnake);

const noScreamingSnakeFromMono: ScreamingSnakeCase<'foobar'> = 'FOOBAR';
expectType<'FOOBAR'>(noScreamingSnakeFromMono);

const nonStringFromNonString: ScreamingSnakeCase<[]> = [];
expectType<[]>(nonStringFromNonString);
1 change: 1 addition & 0 deletions ts41/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export {PascalCasedPropertiesDeep} from './pascal-cased-properties-deep';
export {SnakeCase} from './snake-case';
export {SnakeCasedProperties} from './snake-cased-properties';
export {SnakeCasedPropertiesDeep} from './snake-cased-properties-deep';
export {ScreamingSnakeCase} from './screaming-snake-case';
export {DelimiterCase} from './delimiter-case';
export {DelimiterCasedProperties} from './delimiter-cased-properties';
export {DelimiterCasedPropertiesDeep} from './delimiter-cased-properties-deep';
Expand Down
40 changes: 40 additions & 0 deletions ts41/screaming-snake-case.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {SplitIncludingDelimiters} from './delimiter-case';
import {SnakeCase} from './snake-case';

/**
Returns a boolean for whether the given array includes the given item.
*/
type Includes<Value extends any[], Item> = {
[P in keyof Value & number as Value[P]]: true;
}[Item] extends true
? true
: false;

/**
Returns a boolean for whether the string is screaming snake case.
*/
type IsScreamingSnakeCase<Value extends string> = Value extends Uppercase<Value>
? Includes<SplitIncludingDelimiters<Lowercase<Value>, '_'>, '_'> extends true
? true
: false
: false;

/**
Convert a string literal to screaming-snake-case.
This can be useful when, for example, converting a camel-cased object property to a screaming-snake-cased SQL column name.
@example
```
import {ScreamingSnakeCase} from 'type-fest';
const someVariable: ScreamingSnakeCase<'fooBar'> = 'FOO_BAR';
```
@category Template Literals
*/
export type ScreamingSnakeCase<Value> = Value extends string
? IsScreamingSnakeCase<Value> extends true
? Value
: Uppercase<SnakeCase<Value>>
: Value;

0 comments on commit ebb5a2d

Please sign in to comment.