๐ [TS] I made Ultimate Random Generator which can make Everything
๐ก Newskategorie: Programmierung
๐ Quelle: dev.to
Outline
I made ultimate random generator which can make everything.
Just call typia.random<T>()
function, then it will generate matched random data.
From now on, don't be plagued by random data creation, especially when constructing mockup data. We just need to call the typia.random<T>()
function with only one line. It will do everything for you.
import typia from "typia";
//----
// RANDOM DATA GENERATION
//----
const member: IMembere = typia.random<IMembere>();
console.log(member);
//----
// SCHEMA DEFINITION
//----
interface IMember {
/**
* @format uuid
*/
id: string;
/**
* @minLength 3
* @maxLength 20
*/
account: string;
/**
* @format email
*/
email: string | null;
sex: "male" | "female";
loginHistories: ILoginHistory[];
}
interface ILoginHistory {
/**
* @format ipv4
*/
ip: string;
success: boolean;
/**
* @format date-time
*/
created_at: string;
}
{
"id": "7ea48b93-d201-4a16-a649-546b41c77459",
"account": "uusucswmjiflzur",
"email": "[email protected]",
"sex": "male",
"loginHistories": [
{
"ip": "101.51.96.72",
"success": false,
"created_at": "2027-05-30T07:35:02.626Z"
}
]
}
Principles
AOT (Ahead of Time) compilation, that's how the typia.random<T>()
function can generate all random data in just one line.
When you write above typia.random<IMember>()
function and compiles the code, typia will analyze the IMember
type. After analyzing, typia will write random data generation code suitable for the IMember
type, in the compilation level.
Below is the actual JavaScript code written by typia, in the compilation level. This is the AOT compilation.
const member = ((generator) => {
const $generator = typia.random.generator;
const $pick = typia.random.pick;
const $ro0 = (_recursive = false, _depth = 0) => ({
id: (generator?.customs ?? $generator.customs)?.string?.([
{
name: "format",
value: "uuid"
}
]) ?? (generator?.uuid ?? $generator.uuid)(),
account: (generator?.customs ?? $generator.customs)?.string?.([
{
name: "minLength",
value: "3"
},
{
name: "maxLength",
value: "20"
}
]) ?? (generator?.string ?? $generator.string)((generator?.integer ?? $generator.integer)(3, 20)),
email: $pick([
() => null,
() => (generator?.customs ?? $generator.customs)?.string?.([
{
name: "format",
value: "email"
}
]) ?? (generator?.email ?? $generator.email)()
])(),
sex: $pick([
() => "male",
() => "female"
])(),
loginHistories: (generator?.array ?? $generator.array)(() => $ro1(_recursive, _recursive ? 1 + _depth : _depth))
});
const $ro1 = (_recursive = false, _depth = 0) => ({
ip: (generator?.customs ?? $generator.customs)?.string?.([
{
name: "format",
value: "ipv4"
}
]) ?? (generator?.ipv4 ?? $generator.ipv4)(),
success: (generator?.boolean ?? $generator.boolean)(),
created_at: (generator?.customs ?? $generator.customs)?.string?.([
{
name: "format",
value: "date-time"
}
]) ?? (generator?.datetime ?? $generator.datetime)()
});
return $ro0();
})();
Supported Types
typia supports every TypeScript type.
So, no matter how complex your type T
is, the typia.random<T>()
function can generate random data for it.
Below types are extreme cases, a nd no problem at all.
- TemplateUnion: extreme template literal type
- ArrayRecursiveUnionExplicit: extreme union type with recursive array
- typia#271: extreme conditional type
Also, typia is ensuring its safety through over 7,500 test functions. Thus, if you need random generator, just use typia.random()
with confidence. It is the most powerful random generator than ever.
import typia from "typia";
export type IBucket = IDirectory | IShortcut | IFile;
export interface IDirectory {
type: "directory";
location: string;
name: string;
children: IBucket[];
}
// NO MATTER EVEN HOW COMPLICATE TYPE COMES
const directory: IDirectory = typia.random<IDirectory>();
Comment Tags
You can specialize random data generation by using comment tags.
Below table shows list of supported comment tags in typia.random<T>()
function, and you can utilize them like below example structure TagExample
.
If you want more comment tags, you can define it by yourself -> Customization
Tag Name | Target Type |
---|---|
`@type {"int"\ | "uint"}` |
@minimum {number} |
number |
@maximum {number} |
number |
@exclusiveMinimum {number} |
number |
@exclusiveMaximum {number} |
number |
@multipleOf {number} |
number |
@step {number} |
number |
@length {number} |
string |
@minLength {number} |
string |
@maxLength {number} |
string |
`@format {"email"\ | "uuid"\ |
{% raw %}@pattern {string}
|
string |
@items {number} |
array |
@minItems {number} |
array |
@maxItems {number} |
array |
export interface TagExample {
/* -----------------------------------------------------------
ARRAYS
----------------------------------------------------------- */
/**
* You can limit array length like below.
*
* @minItems 3
* @maxItems 10
*
* Also, you can use `@items` tag to fix length.
*
* @items 5
*
* Furthermore, you can use additional tags for each item.
*
* @type uint
* @format uuid
*/
array: Array<string|number>;
/**
* If two-dimensional array comes, length limit would work for
* both 1st and 2nd level arrays. Also using additional tags
* for each item (string) would still work.
*
* @minItems 5
* @maxItems 10
* @format url
*/
matrix: string[][];
/* -----------------------------------------------------------
NUMBERS
----------------------------------------------------------- */
/**
* Type of number.
*
* It must be one of integer or unsigned integer.
*
* @type int
* @type uint
*/
type: number;
/**
* You can limit range of numeric value like below.
*
* @minimum 5
* @maximum 10
*
* Also, you can use exclusive tags instead
*
* @exclusiveMinimum 4
* @exclusiveMaximum 11
*/
range: number;
/**
* Step tag requires minimum or exclusiveMinimum tag.
*
* 3, 13, 23, 33, ...
*
* @step 10
* @exclusiveMinimum 3
*/
step: number;
/**
* Value must be multiple of the given number.
*
* -5, 0, 5, 10, 15, ...
*
* @multipleOf 5
*/
multipleOf: number;
/* -----------------------------------------------------------
STRINGS
----------------------------------------------------------- */
/**
* You can limit string length like below.
*
* @minLength 3
* @maxLength 10
*
* Also, you can use `@length` tag to fix length.
*
* @length 7
*/
length: string;
/**
* Mobile number composed by only numbers.
*
* @pattern ^0[0-9]{7,16}
* -> RegExp(/[0-9]{7,16}/).test("01012345678")
*/
mobile: string;
/**
* E-mail address.
*
* @format email
*/
email: string;
/**
* UUID value.
*
* @format uuid
*/
uuid: string;
/**
* URL address.
*
* @format url
*/
url: string;
/**
* IPv4 address.
*
* @format ipv4
*/
ipv4: string;
/**
* IPv6 address.
*
* @format ipv6
*/
ipv6: string;
/**
* `YYYY-MM-DD`
*
* @format date
*/
date: string;
/**
* Same with `Date.toISOString()`
*
* @format date-time
*/
datetime: string;
}
Customization
As you can see from above Supported Comment Tags corner, typia.random<T>()
can utilize comment tags for speicifying the random data generation.
By the way, if someone wants additional comment tgas that is not supported by typia, then how should do?
The answer is just define your own custom comment tags like below:
import typia from "typia";
export interface TagCustom {
/**
* Regular feature supported by typia
*
* @format uuid
*/
id: string;
/**
* Custom feature composed with "$" + number
*
* @dollar
*/
dollar: string;
/**
* Custom feature composed with string + "abcd"
*
* @postfix abcd
*/
postfix: string;
/**
* Custom feature meaning x^y
*
* @powerOf 10
*/
log: number;
}
const data: TagCustom = typia.random<TagCustom>({
customs: {
string: (tags: typia.IRandomGenerator.ICommentTag[]) => {
if (tags.find((t) => t.name === "dollar") !== undefined)
return "$" + RandomGenerator.integer();
const postfix = tags.find((t) => t.name === "postfix");
if (postfix !== undefined)
return RandomGenerator.string() + postfix.value;
},
number: (tags: typia.IRandomGenerator.ICommentTag[]) => {
const powerOf = tags.find((t) => t.name === "powerOf");
if (powerOf !== undefined)
return Math.pow(
Number(powerOf.value),
RandomGenerator.integer(1, 4),
);
},
}
});