let\'s say I have this C# class
public class Product
{
public Guid Id { get; set; }
public string ProductName { get; set; }
public Decimal Price { g
Guids are usually represented as strings in Javascript, so the simplest way to represent the GUID is as a string. Usually when serialization to JSON occurs it is represented as a string, so using a string will ensure compatibility with data from the server.
To make the GUID different from a simple string, you could use branded types:
type GUID = string & { isGuid: true};
function guid(guid: string) : GUID {
return guid as GUID; // maybe add validation that the parameter is an actual guid ?
}
export interface Product {
id: GUID;
productName: string;
price: number;
level: number;
}
declare let p: Product;
p.id = "" // error
p.id = guid("guid data"); // ok
p.id.split('-') // we have access to string methods
This article has a bit more of a discussion on branded types. Also the typescript compiler uses branded types for paths which is similar to this use case.
Another alternative is using following NPM package:
guid-typescript which you can find here: https://www.npmjs.com/package/guid-typescript
Then it will be just like this:
import { Guid } from "guid-typescript";
export class Product {
id: Guid;
productName: string;
price: number;
level: number;
}
For most of my use cases, I need to accept a deserialized string that comes from an API, but also generate new ids and validate them once they're on the client.
Both of the previous answers are great & each tackle a piece of the problem, where this gist combines the typing from the accepted answer and the spirit of the guid-typescript package: https://gist.github.com/dperish/b9b2bbc6f10c686921c0f216bfe4cb40
class GuidFlavoring<FlavorT> {
// tslint:disable-next-line: variable-name
_type?: FlavorT;
}
/** A **guid** type, based on **string** */
type GuidFlavor<T, FlavorT> = T & GuidFlavoring<FlavorT>;
/** A **guid**-flavored string primitive, supported by factory methods in the **Guid** class
*/
export type guid = GuidFlavor<string, 'guid'>;
/** A container for factory methods, which support the **guid** type */
export class Guid {
/** Specifies the RegExp necessary to validate **guid** values */
private static validator: RegExp = new RegExp(
'^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$',
'i'
);
/** Generates a random, hyphenated **guid** value */
static newGuid = (): guid =>
[
Guid.generateGuidSegment(2),
Guid.generateGuidSegment(1),
Guid.generateGuidSegment(1),
Guid.generateGuidSegment(1),
Guid.generateGuidSegment(3),
].join('-');
/** Generates a new **guid**, with the empty/least possible value
* @returns {guid} 00000000-0000-0000-0000-000000000000
*/
static empty = (): guid => '00000000-0000-0000-0000-000000000000';
/** Generates a new **guid**, with the full/greatest possible value
* @returns {guid} ffffffff-ffff-ffff-ffffffffffff
*/
static full = (): guid => 'ffffffff-ffff-ffff-ffffffffffff';
/** Evaluates whether the supplied **guid** is equal to the empty/least possible value */
static isEmpty = (value: guid) => value === Guid.empty();
/** Evaluates whether the supplied *guid* is equal to the empty/greatest possible value */
static isFull = (value: guid) => value === Guid.full();
/** Evaluates whether the supplied value is a valid **guid** */
static isValid = (value: string | guid): boolean =>
Guid.validator.test(value);
/** Generates a specified number of double-byte segements for **guid** generation */
private static generateGuidSegment(count: number): string {
let out = '';
for (let i = 0; i < count; i++) {
// tslint:disable-next-line:no-bitwise
out += (((1 + Math.random()) * 0x10000) | 0)
.toString(16)
.substring(1)
.toLowerCase();
}
return out;
}
}