Skip to content

Commit

Permalink
rename arrays to lists and maps to dictionaries
Browse files Browse the repository at this point in the history
  • Loading branch information
pghalliday committed Feb 5, 2021
1 parent b4fae29 commit 97c4ee5
Show file tree
Hide file tree
Showing 39 changed files with 218 additions and 231 deletions.
61 changes: 24 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {TsTypeGenerator} from "@pghalliday/ts-type-generator";

new TsTypeGenerator()
// TODO: add types here
.generate(resolve(__dirname, "../lib"));
.generate(resolve(__dirname, "../index.ts"));
```

You can then run this using `ts-node`:
Expand All @@ -36,7 +36,7 @@ You can then run this using `ts-node`:
ts-node ./types/src/index.ts
```

As it stands this will not create any types or type guards as none have been defined. However, it will create a `./types/lib` directory and copy in some library files for use in generated type files.
As it stands this will not create any types or type guards as none have been defined. However, it will create a `./types/index.ts` module and copy in some utility functions for use in generated type guards.

### Adding types

Expand All @@ -62,7 +62,7 @@ new TsTypeGenerator()
.property("userId", stringType)
.property("message", stringType)
)
.generate(resolve(__dirname, "../lib"));
.generate(resolve(__dirname, "../index.ts"));
```

This will generate 2 types equivalent to this:
Expand Down Expand Up @@ -91,30 +91,21 @@ export function isMessage(value: unknown): value is Message {
}
```

These will be generated in their own files under the output `lib` directory. As such you can import them like this:
You can import them like this:

```typescript
import {User, isUser} from './types/lib/User'
import {Message, isMessage} from './types/lib/User'
import {User, isUser, Message, isMessage} from "./types";
```

So what's happening here. Well the main thing to know is that any number of types can be added and each type and the types they depend on will result in a generated type file.
So what's happening here. Well the main thing to know is that any number of types can be added and each type, and the types they depend on, will be added to the generated types module.

Types all have the same base `Type` class, so they can be used wherever a type is required.
Types all have the same base `Type` class, so they can be re-used wherever a type is required.

Some primitive types are provided as constants. Here we are using the `stringType` as an alias for `string`. We have to use an instance of `Type` so this has been created as a singleton. Using the `stringType` will result in a `String` type file being created with the following content:

```typescript
export type StringTypeTs = string;

export function isStringType(value: unknown): value is StringTypeTs {
...
}
```
Some primitive types are provided as constants. Here we are using the `stringType` as an alias for `string`. We have to use an instance of `Type` so this has been created as a singleton for convenience.

### Anonymous types

When defining types and sub types, you may not always care what they're called. As such, type names are always optional. As it happens, when the type file is generated, a name will also be generated but this is just an implementation detail.
When defining types and sub-types, you may not always care what they are called. As such, type names are always optional. As it happens, when the type file is generated, a name will also be generated but this is an internal implementation detail. Anonymous types will not be exported from the types module.

For example to create a more complex structure where we only care about the top level type name:

Expand All @@ -132,7 +123,7 @@ new TsTypeGenerator()
.property("lastName", stringType)
)
)
.generate(resolve(__dirname, "../lib"));
.generate(resolve(__dirname, "../index.ts"));
```

Which will create a named type and type guard equivalent to:
Expand All @@ -153,22 +144,20 @@ export function isUser(value: unknown): value is User {

### Type constants

The following `Type` constants are provided as primitive types:
The following `Type` constants are provided as convenience primitive types:

- `stringType` - the `string` primitive
- `numberType` - the `number` primitive
- `booleanType` - the `boolean` primitive

The following are provided as convenience `Type` instances:
The following `Type` constants are provided as convenience primitive collection instances:

- `stringArrayType` - for arrays of `string` primitives
- `stringMapType` - for maps of `string` primitives
- `numberArrayType` - for arrays of `number` primitives
- `numberMapType` - for maps of `number` primitives
- `booleanArrayType` - for arrays of `boolean` primitives
- `booleanMapType` - for maps of `boolean` primitives

NB. Only maps keyed by `string` are supported.
- `stringListType` - for lists of `string` primitives
- `stringDictionaryType` - for dictionaries of `string` primitives
- `numberListType` - for lists of `number` primitives
- `numberDictionaryType` - for dictionaries of `number` primitives
- `booleanListType` - for lists of `boolean` primitives
- `booleanDictionaryType` - for dictionaries of `boolean` primitives

### Type classes

Expand All @@ -194,24 +183,22 @@ new UnionType(NAME?)
...
```
#### `ArrayType`
#### `ListType`
To define an array type.
To define a list type.
```typescript
new ArrayType(TYPE, NAME?)
new ListType(TYPE, NAME?)
```
#### `MapType`
#### `DictionaryType`
To define a map type.
To define a dictionary type.
```typescript
new MapType(TYPE, NAME?)
new DictionaryType(TYPE, NAME?)
```
NB. Only `string` keys are supported for maps.
#### `StringLiteralType`
To define a `string` literal type.
Expand Down
6 changes: 6 additions & 0 deletions files/isDictionaryOf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function isDictionaryOf<X extends {}, Y>(obj: X, typeGuard: (value: unknown) => value is Y): obj is X & { [key: string]: Y } {
for (const key in obj) {
if (!typeGuard(obj[key])) return false;
}
return true;
}
6 changes: 0 additions & 6 deletions files/isMapOf.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/TsTypeGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import isUndefined from "lodash/isUndefined"
import {readFileSync} from "fs";

const HAS_OWN_PROPERTY_DEFINITION = readFileSync(join(FILES_DIR, 'hasOwnProperty.ts')).toString()
const IS_MAP_OF_DEFINITION = readFileSync(join(FILES_DIR, 'isMapOf.ts')).toString()
const IS_DICTIONARY_OF_DEFINITION = readFileSync(join(FILES_DIR, 'isDictionaryOf.ts')).toString()
const EXPORT_PREFIX = 'export '

function collectTypes(types: Type[], typeMap: Record<string, Type>): Record<string, Type> {
Expand Down Expand Up @@ -56,7 +56,7 @@ export class TsTypeGenerator {
await file.write(type.getTypeGuardDefinition())
}
await file.write(HAS_OWN_PROPERTY_DEFINITION)
await file.write(IS_MAP_OF_DEFINITION)
await file.write(IS_DICTIONARY_OF_DEFINITION)
await file.close()
}
}
4 changes: 0 additions & 4 deletions src/constants/booleanArrayType.ts

This file was deleted.

4 changes: 4 additions & 0 deletions src/constants/booleanDictionaryType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {DictionaryType} from "../types";
import {booleanType} from "./booleanType";

export const booleanDictionaryType = new DictionaryType(booleanType)
4 changes: 4 additions & 0 deletions src/constants/booleanListType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {ListType} from "../types";
import {booleanType} from "./booleanType";

export const booleanListType = new ListType(booleanType)
4 changes: 0 additions & 4 deletions src/constants/booleanMapType.ts

This file was deleted.

12 changes: 6 additions & 6 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export * from './stringType'
export * from './numberType'
export * from './booleanType'
export * from './stringArrayType'
export * from './numberArrayType'
export * from './booleanArrayType'
export * from './stringMapType'
export * from './numberMapType'
export * from './booleanMapType'
export * from './stringListType'
export * from './numberListType'
export * from './booleanListType'
export * from './stringDictionaryType'
export * from './numberDictionaryType'
export * from './booleanDictionaryType'
4 changes: 0 additions & 4 deletions src/constants/numberArrayType.ts

This file was deleted.

4 changes: 4 additions & 0 deletions src/constants/numberDictionaryType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {DictionaryType} from "../types";
import {numberType} from "./numberType";

export const numberDictionaryType = new DictionaryType(numberType)
4 changes: 4 additions & 0 deletions src/constants/numberListType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {ListType} from "../types";
import {numberType} from "./numberType";

export const numberListType = new ListType(numberType)
4 changes: 0 additions & 4 deletions src/constants/numberMapType.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/constants/stringArrayType.ts

This file was deleted.

4 changes: 4 additions & 0 deletions src/constants/stringDictionaryType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {DictionaryType} from "../types";
import {stringType} from "./stringType";

export const stringDictionaryType = new DictionaryType(stringType)
4 changes: 4 additions & 0 deletions src/constants/stringListType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import {ListType} from "../types";
import {stringType} from "./stringType";

export const stringListType = new ListType(stringType)
4 changes: 0 additions & 4 deletions src/constants/stringMapType.ts

This file was deleted.

8 changes: 4 additions & 4 deletions src/types/MapType.ts → src/types/DictionaryType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import {join} from "path";
import {TEMPLATES_DIR} from "../util/constants";
import Mustache from "mustache";

const TYPE_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'MapType.ts.mustache')).toString()
const TYPE_GUARD_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'MapType.guard.ts.mustache')).toString()
const TYPE_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'DictionaryType.ts.mustache')).toString()
const TYPE_GUARD_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'DictionaryType.guard.ts.mustache')).toString()

export class MapType implements Type {
export class DictionaryType implements Type {
exportParams: ExportParams
type: Type

constructor(type: Type, name?: string) {
this.exportParams = getExportParams('Map', name)
this.exportParams = getExportParams('Dictionary', name)
this.type = type
}

Expand Down
8 changes: 4 additions & 4 deletions src/types/ArrayType.ts → src/types/ListType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import {join} from "path";
import {TEMPLATES_DIR} from "../util/constants";
import Mustache from "mustache";

const TYPE_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'ArrayType.ts.mustache')).toString()
const TYPE_GUARD_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'ArrayType.guard.ts.mustache')).toString()
const TYPE_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'ListType.ts.mustache')).toString()
const TYPE_GUARD_DEFINITION_TEMPLATE = readFileSync(join(TEMPLATES_DIR, 'ListType.guard.ts.mustache')).toString()

export class ArrayType implements Type {
export class ListType implements Type {
exportParams: ExportParams
type: Type

constructor(type: Type, name?: string) {
this.exportParams = getExportParams('Array', name)
this.exportParams = getExportParams('List', name)
this.type = type
}

Expand Down
4 changes: 2 additions & 2 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ export * from './NumberLiteralType'
export * from './BooleanLiteralType'
export * from './UnionType'
export * from './InterfaceType'
export * from './ArrayType'
export * from './MapType'
export * from './ListType'
export * from './DictionaryType'
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
function is{{{name}}}(value: unknown): value is {{{name}}} {
if (!(typeof value === "object")) return false;
if (value === null) return false;
return isMapOf(value, is{{{type}}});
return isDictionaryOf(value, is{{{type}}});
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions test/src/TsTypeGenerator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const TYPES_FILE_NAME = 'types.ts'
const OUTPUT_FILE = join(OUTPUT_DIRECTORY, TYPES_FILE_NAME)

const HAS_OWN_PROPERTY_DEFINITION = readFileSync(join(FILES_DIR, 'hasOwnProperty.ts')).toString()
const IS_MAP_OF_DEFINITION = readFileSync(join(FILES_DIR, 'isMapOf.ts')).toString()
const IS_DICTIONARY_OF_DEFINITION = readFileSync(join(FILES_DIR, 'isDictionaryOf.ts')).toString()
const EXPORT_PREFIX = 'export '

const TYPE_1 = new TestType('Type1', true)
Expand Down Expand Up @@ -48,7 +48,7 @@ const EXPECTED_OUTPUT_FILE_CONTENT =
TYPE_6.getTypeDefinition() +
TYPE_6.getTypeGuardDefinition() +
HAS_OWN_PROPERTY_DEFINITION +
IS_MAP_OF_DEFINITION
IS_DICTIONARY_OF_DEFINITION

describe('TsTypeGenerator', () => {
let instance: TsTypeGenerator
Expand Down
21 changes: 0 additions & 21 deletions test/src/constants/booleanArrayType.test.ts

This file was deleted.

21 changes: 21 additions & 0 deletions test/src/constants/booleanDictionaryType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {booleanDictionaryType, DictionaryType, booleanType} from "../../../src"

const GENERATED_TYPE_NAME_REGEXP = new RegExp('^__TTG_Anonymous_Dictionary_[0-9]+$')

describe('booleanDictionaryType', () => {
it('should be a DictionaryType', () => {
booleanDictionaryType.should.be.an.instanceOf(DictionaryType);
})

it('should have the correct name', () => {
booleanDictionaryType.getName().should.match(GENERATED_TYPE_NAME_REGEXP)
})

it('should not be exported', () => {
booleanDictionaryType.isExported().should.be.false
})

it('should be an array of booleans', () => {
booleanDictionaryType.type.should.equal(booleanType);
})
})
21 changes: 21 additions & 0 deletions test/src/constants/booleanListType.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {booleanListType, ListType, booleanType} from "../../../src"

const GENERATED_TYPE_NAME_REGEXP = new RegExp('^__TTG_Anonymous_List_[0-9]+$')

describe('booleanListType', () => {
it('should be a ListType', () => {
booleanListType.should.be.an.instanceOf(ListType);
})

it('should have the correct name', () => {
booleanListType.getName().should.match(GENERATED_TYPE_NAME_REGEXP)
})

it('should not be exported', () => {
booleanListType.isExported().should.be.false
})

it('should be an array of booleans', () => {
booleanListType.type.should.equal(booleanType);
})
})
Loading

0 comments on commit 97c4ee5

Please sign in to comment.