k9b
k9b

Reputation: 1493

How to cast a redis entry to a typescript type?

I have a class that stores a hashmap to a redis instance like so.

static async store(obj: KeyObject) {
    return client.hmset(`obj:${obj.objKey}`, {
      id: obj.id, // number
      ownerId: obj.ownerId.toBase58(), // string
      key: obj.key, // number
    });
  }

When I get get this row from redis, it returns like

{ 
  id : '1',
  ownerId: '2',
  key: '3'
}

I am looking to get the id parameter as a number (like it was when I put it in)

I can cast it specifically as a number when I use it in my program, but I rather just cast it to the whole object when getting it like

client.hgetall(`obj:${objKey}`) as KeyObject

is this possible?

Thanks!

Upvotes: 1

Views: 1316

Answers (1)

Rubydesic
Rubydesic

Reputation: 3476

No, it's not possible it's not due to Typescript. When Redis gives you back the id, it's NOT a number, (this is an implementation detail of Redis, which makes no distinction between strings and numbers, nothing to do with js or ts). You'll need to manually change it back:

const row = { 
  id : '1',
  ownerId: '2',
  key: '3'
}

row.id = Number(row.id)

If you have multiple keys which you need to turn back to a number and you're feeling lazy, you can make a helper function:

type ConvertKeys<Object, Keys extends Array<keyof Object>, To> = { 
  [P in keyof Object]: P extends Keys[number] ? To : Object[P]
}

function convertKeys<O, K extends Array<keyof O>, T>(
  converter: (arg: any) => T,
  obj: O, 
  ...keys: K
): ConvertKeys<O, K, T> {
  // type system is too stupid to see how this transformation works
  const copy = Object.assign({}, obj) as any
  keys.forEach(k => copy[k] = converter(copy[k]))
  return copy
}

And then use it:

const fixedRow = convertKeys(Number, row, "id", "key")
const id: number = fixedRow.id; // A-OK!

Upvotes: 2

Related Questions