Node.js + TypeScript + RedisJSON

huangapple go评论56阅读模式
英文:

Nodejs + Typescript + RedisJSON

问题

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 Node.js + TypeScript + RedisJSON

Thanks a lot

英文:

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 Node.js + TypeScript + RedisJSON

Thanks a lot

答案1

得分: 3

RedisJSON 类型声明要求您提供的 JSON 对象具有索引签名声明。您的 myUser 接口没有这个声明,因此它们不兼容。您需要使用类型(下面会详细说明)而不是接口,或者在接口声明中显式包含索引签名。

以下代码有效:

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

  // 您可以在此处使用类型断言来告诉 TypeScript GET 将返回哪种类型。
  // 您应该包含 'null' 来强制您检查空结果并防止运行时错误。
  const redisUser = await redis.json.get('key') as MyUser | null;
  console.log(redisUser);
}

代码提供的解释:

您提供的代码引发以下 TypeScript 错误:

类型 'myUser' 无法分配给类型 'RedisJSONObject'。
类型 'myUser' 中缺少类型 'string' 的索引签名。

redis.json.set() 方法期望第三个参数与 RedisJSON 兼容,RedisJSON 的定义如下:

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

这个 [key: string]: RedisJSON; 是一个索引签名声明。

当将 MyUser 定义为接口时,它与 RedisJSONObject 不兼容,因为接口不包含索引声明,除非您显式定义它。

在 TypeScript 中,已知类型和接口是“可互换的”。然而,它们的行为有微妙的差异。

除了主要差异之外,类型在不显式定义的情况下包含索引签名,而接口不包含。

这就是为什么在这种情况下,将 MyUser 重新定义为类型可以解决错误的原因。

希望这有所帮助!

英文:

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!

huangapple
  • 本文由 发表于 2023年5月24日 21:04:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76323867.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定