multiformats / js-cid

CID implementation in JavaScript
MIT License
98 stars 39 forks source link

Typescript is confused by constructor overload in the defs #128

Closed Gozala closed 3 years ago

Gozala commented 3 years ago

Current type defs for the CIDs have bunch of overloads for the construction function, which seems to confuse typescript in some call patterns.

achingbrain commented 3 years ago

For example:

/**
 * @param {string|Uint8Array|CID} cid
 * ...
 */
function (cid) {
  cid = new CID(cid)
  //...
}
No overload matches this call.
  Overload 1 of 4, '(cid: CID): CID', gave the following error.
    Argument of type 'string | CID | Uint8Array' is not assignable to parameter of type 'CID'.
      Type 'string' is not assignable to type 'CID'.
  Overload 2 of 4, '(str: string): CID', gave the following error.
    Argument of type 'string | CID | Uint8Array' is not assignable to parameter of type 'string'.
      Type 'CID' is not assignable to type 'string'.
  Overload 3 of 4, '(buf: Uint8Array): CID', gave the following error.
    Argument of type 'string | CID | Uint8Array' is not assignable to parameter of type 'Uint8Array'.
      Type 'string' is not assignable to type
Gozala commented 3 years ago

Ok here is the solution to all these problems:

https://www.typescriptlang.org/play?#code/PQKhCgAIUhhAbAhgZ2ZATgUwA5eZgOwBcBLAgc0kTgEkARSAAwB4BbAIxUwD5mA3TOmQkA9gV6sAxiIAmmSRIAWKRd0ZQYAGipo5AMzKYZkMpADaJbPBnBJJGQF0AFIqJFsyAFzBg5EkUUAV3YAOmlWYFZA+FI9EXRWRCJkW3sAShCNYHA5SSQsSDyUNFh6SABvKEhQCEg6mFgsJMwqSAJMAHdaOky66CroSAAVRRbEeHJ4-0VWSDj0KnRyQNZCIhMCbED1kjR0EUDyRXgAT08BmEYri5M9SCc7GTSbuoBabkKmojHCkWwTm6YeD4W73ZBEdDPPowOokO5OACM4MKygWu0gYkgURiJE4IKIiHY8EwaUg726kAAyhCyOQXpAgSDyexkABWAAcDII0jkxmxpGUyEUgOBLTh9wAqmQiOyAILodCIE5Q+p9cWI5HsE7fExoAAMGIWCNJ5NKdHpjJa5P5JEFwuhDNFoKcADkVuxBCrBm8PtICOD0IFJOszZAtZBsIh0Mkbld1NCbgABTAAD0QrCsmBu7S6Zqc-EEwjE3G0zB58hLkDY0QFKkr1ZxeMwLvTPC9MBz3Xzj2p6G47banS7ZfsIS132Q-ezQ7zDdrQqnDs7s5ZHK55b5NdtdYHy-o3fsi-q2TqfoDQaI8ScA0gAiEogInm6ADVCw-NDfy5InwHaZAAD5tO6ggfn0WI1naT5SsQcoKkqoF9DaTYtqsAD8P40hQVRpAA3FUZ4QheV6PE+Zr-r+FD-tBMryoqyp4VUNQ3CMLR3kWBAYncAQtGavTHlUTQyGIpy3m+YikfQr73mIDF1ExDosb8uScZA3HdHx0AnhgmCIEJBAiV+GHoLSsnVGAzGjEp8gqWpoamP4aAEMBCzzKwGkgFpgnCScVlPk5HCCKZ8mqopNp2jZlm8Rcnk6XpIlhSoUHSrBdFBeZDoALJbk2bStjokAUeQ7kxbp3ngY2XAoZgRkmeAjHpSFkVlCgrSMNRKVKvG-F1F5+k+eOmBeJA7W0UqaW1I1LS4JgBgphFPH0MVAmxWV02zUlMGjSc403LAYh3usl6tKGIh3GxD5MHqjBLXUl7PnqThpBJdA7Q6e0EAdqkiMdZSnaJ0kcYwCLXdFVR3Qij3Pa9qoAKLcrILS2WU0rfdQhXuUmkaKrMOUAEJcOush-kdgT4DdX34-gcMbr2tJOE26EFZh5BPUzxkUNDgzUwjqlNQwKOtOjoO3SItMUPTXCM4VrOFZzMCUoIJDjCQABeiOoxGSCmCI7AAFbyEQ5OXgAUpSADyLqQxUVnfmzJn-exT4GoBCI4ZAkHDclW2QAAvnLcAiBmUYtJgACOgTK0QPkdNMVAECI3ELFFCYOomWPphiifDJZCejEni3Cwy4fjMgTi54IT6IAQypPuwIgiMSVf+0Mg07Fxll+AIHFkFsOxoNQfDK8YJ16wb7nZ-sHRoOK-i6m0CcY6n6ezOXCyKav6mF+CSQkJIt5D80ear5X1es3wIj2KZ2+kHvux5qwJApkYJ811ij9GHPZpXwSN820NABK8h4gyGYIVbQ-kPR9jwj7OqUdsALToFJdikAAC8kA9T-gRHVAicx9izDQQ8ewnhCpUS9nBE4-4zSkhQR8PcdBCFPHADgrGIICEkWlqg2hM59yPGeDgvIYgWhsKIVQzhg5cw8PSEwsQyJpD-FQfcEioiaHiK7I8EI50xDaHUV+bRo4EpCj4TI9YuQebCJkJ4Ea5DqFcIkfQ3h0j-TrEkF8IR9xNGPggSBG2flnLaAMYoDaNFrFiMqLCeEHjUEoLQc7QCkToloONNbG8WAiCBHQBxOhTgPHaIRpIfxW47Qqh9o6EEYSwK80npAGGCorwAHIaAfSHg7B8dTingB9kAA

Inline below

/**
 * Class representing a CID `<mbase><version><mcodec><mhash>`
 * , as defined in [ipld/cid](https://github.com/multiformats/cid).
 */
declare class CID {
  /**
   * Create a new CID.
   *
   * The algorithm for argument input is roughly:
   * ```
   * if (cid)
   *   -> create a copy
   * else if (str)
   *   if (1st char is on multibase table) -> CID String
   *   else -> bs58 encoded multihash
   * else if (Uint8Array)
   *   if (1st byte is 0 or 1) -> CID
   *   else -> multihash
   * else if (Number)
   *   -> construct CID by parts
   * ```
   *
   * @example
   * new CID(<version>, <codec>, <multihash>, <multibaseName>)
   * new CID(<cidStr>)
   * new CID(<cid.bytes>)
   * new CID(<multihash>)
   * new CID(<bs58 encoded multihash>)
   * new CID(<cid>)
   */
  constructor(
    version: CIDVersion,
    codec: string | number,
    multhash: Uint8Array,
    multibaseName?: string
  );
  constructor(cid: CID|string|Uint8Array);

  /**
   * The version of the CID.
   */
  readonly version: CIDVersion;

  /**
   * The codec of the CID.
   */
  readonly codec: string;

  /**
   * The codec of the CID in its number form.
   */
  readonly code: number;

  /**
   * The multihash of the CID.
   */
  readonly multihash: Uint8Array;

  /**
   * Multibase name as string.
   */
  readonly multibaseName: string;

  /**
   * The CID as a `Uint8Array`
   */
  readonly bytes: Uint8Array;

  /**
   * The prefix of the CID.
   */
  readonly prefix: Uint8Array;

  /**
   * Convert to a CID of version `0`.
   */
  toV0(): CID;

  /**
   * Convert to a CID of version `1`.
   */
  toV1(): CID;

  /**
   * Encode the CID into a string.
   *
   * @param base Base encoding to use.
   */
  toBaseEncodedString(base?: string): string;

  /**
   * Encode the CID into a string.
   */
  toString(base?: string): string;

  /**
   * Serialize to a plain object.
   */
  toJSON(): { codec: string; version: 0 | 1; hash: Uint8Array };

  /**
   * Compare equality with another CID.
   *
   * @param other The other CID.
   */
  equals(other: any): boolean;

  /**
   * Test if the given input is a valid CID object.
   * Throws if it is not.
   *
   * @param other The other CID.
   */
  static validateCID(other: any): void;

  static isCID(mixed: any): mixed is CID;

  static codecs: Record<string, number>;
}

type CIDVersion = 0|1

const from = (cid:string|Uint8Array|CID) => new CID(cid)
const parse = (cid:string) => new CID(cid)
const clone = (cid:CID) => new CID(cid)
const copy = (cid:CID) => new CID(cid.version, cid.codec, cid.multihash)
const decode = (cid:Uint8Array) => new CID(cid)
const create = (version:number, codec: number, multihash: Uint8Array) => {
  if (version === 0 || version === 1) { 
    return new CID(version, codec, multihash)
  } else {
      throw Error('Invalid version')
  }
}
achingbrain commented 3 years ago

🙏 Please PR 😄

rvagg commented 3 years ago

OK, so the fix here addresses assigning to a CID|string|Uint8Array from a function that only returns either CID, string, or Uint8Array. 🙃. It's really a TypeScript bug that we have to address and not technically a bug in our definitions, right?