1

I just started programming a little bit with nodejs, typescript and redis. Unfortunately I run into a problem with redis: I define an interface of data to be stored in redis. However, as soon as I write the type behind the variable redis complains to me. Same when i get Keys from redis: How to tell Typescript which type the data is?

Example:


async function RedisQuestion() {
  const redis = createClient();

  interface userLogins {
    token: string;
    active: boolean;
  }

  interface myUser {
    name: string;
    id: string;
    logins: userLogins[];
  }

  const objToStore: myUser = {
    name: "Karl Mustermann",
    id: "1",
    logins: [
      {
        token: "1234",
        active: true
      },
      {
        token: "2345",
        active: false
      }
    ]
  };

  await redis.json.set("key", "$", objToStore);

  const redisResult = redis.json.get("key") as myUser;
  console.log(redisUser);
}

The way it works is if i say

await redis.json.set("key", "$", objToStore as any);

And if i get values from redis:

await redis.json.get("key") as any as myUser;

But there must be a better way?! Hope you can help :)

Thanks a lot

peacemaker
  • 57
  • 4

1 Answers1

2

TL;DR

RedisJSON type declaration expects the json object you provide to have an index signature declaration. Your myUser interface doesn't have it, therefore they are incompatible.
You need to either use a type (more on that below) instead of an interface, or explicitly include the index signature in your interface declaration.

The following code works:

type UserLogins = {
  token: string;
  active: boolean;
}

type MyUser = {
  name: string;
  id: string;
  logins: UserLogins[];
}

async function redisQuestion() {
  const redis = createClient();

  const objToStore: MyUser = {
    name: 'Karl Mustermann',
    id: '1',
    logins: [],
  };

  await redis.json.set('key', '$', objToStore);

  // You can use type assertion here to tell Typescript which type will the GET return.
  // You should include the 'null' to force you to check for a null result and prevent
  // runtime errors.
  const redisUser = await redis.json.get('key') as MyUser | null;
  console.log(redisUser);
}

Explanation

The code you provide throws the following Typescript error:

Type 'myUser' is not assignable to type 'RedisJSONObject'.
Index signature for type 'string' is missing in type 'myUser'

The method redis.json.set() expects the third parameter to be type-compatible with RedisJSON, which is defined like so:

type RedisJSON = null | boolean | number | string | Date | RedisJSONArray | RedisJSONObject;
interface RedisJSONObject {
    [key: string]: RedisJSON;
    [key: number]: RedisJSON;
}

This [key: string]: RedisJSON; is an index signature declaration.

When defining MyUser as an interface, you make it incompatible with RedisJSONObject because interfaces don't include an index declaration unless you explicitly define it.

It is known that, in Typescript, types and interfaces are "interchangeable". However, there are subtle differences in how they behave.

Apart from the key differences, types include an index signature without explicitly defining it, whereas interfaces don't.

That's why, in this case, redefining MyUser as a type solves the error.

I hope that helps!

mvaker
  • 36
  • 2