Richard77
Richard77

Reputation: 21651

How to represent Guid in typescript?

let's say I have this C# class

public class Product
{
   public Guid Id { get; set; }
   public string ProductName { get; set; }
   public Decimal Price { get; set; }
   public int Level { get; set; }
}

The equivalent typescript would be something like:

export class Product {
  id: ???;
  productName: string;
  price: number;
  level: number;
}

How to represent Guid in typescript?

Upvotes: 40

Views: 59415

Answers (3)

dperish
dperish

Reputation: 1571

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;
  }
}

Upvotes: 0

Jagjit Singh
Jagjit Singh

Reputation: 751

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;
}

Upvotes: 23

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250106

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.

Upvotes: 36

Related Questions