Currently types are located in https://www.npmjs.com/package/@types/ioredis
Types ares out of sync with ioredis repo.
It would be easier to fix and maintain there.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 7 days if no further activity occurs, but feel free to re-open a closed issue if needed.
Bumping to keep this issue alive.
I recently ran into an issue with @types/ioredis - namely that it didn't include the geo* family of functions.
Seeing as this library is written in TypeScript I hope the maintainers are open to moving types into this repo.
Here is the author's answer on why declarations are not part of this repo: https://github.com/luin/ioredis/pull/981#issuecomment-538718567
I am confused. I must be missing something.
.ts@types/ioredis which I did. @types/ioredis seems to be relatively off, as for example. xread(...args: ValueType[]): Array<[string, string[]]>;, which should union null as result, and even the type seems to be incomplete. For now, I do (which is not optimimum)type StreamName = string;
type EntryId = string;
type StreamReadRaw = [StreamName, [EntryId, string[]][]][];
declare module "ioredis" {
interface Redis {
xread(...args: ValueType[]): StreamReadRaw | null;
}
}
So,
a) I am not sure if @types/ioredis is generated from this project .ts, but right now it seems really off.
b) I do not know how many more apis defined in @types/ioredis are not aligned with ioredis
c) I read the #981 #issuecomment-538718567, but even having a "any" for some of those corner cases before generic can be figured out would be nice. Right now, I am not even sure how the types can be used (at last for xread)
We plan to move to ioredis from node-redis mostly because of the native promise/async/await support, but those typing issues are making us a little worried.
I analyzed this issue for a few hours. I think the biggest drawback is that the used COMMAND command does not describe the return type nor does it describe the type of the input parameters. So you could say, that it is actually like the redis-cli, where you just type in string commands, which then will be interpreted and the input values be converted in redis to the needed data type.
So a automated generated typedefinition would be usually full with any types.
So a get currently is typed as:
get(key: KeyType, callback: Callback<string | null>): void;
get(key: KeyType): Promise<string | null>;
but in an automated generation we would have
get(key: KeyType, callback: Callback<any>): void;
get(key: KeyType): Promise<any>;
as we dont know the return value, because the command COMMAND does not provide the necessary information.
If we could determine, how the redis documentation page is generated, then maybe we can use the same source to write proper typings.
redis-doc is unfortunately not in a machine readable style.
but we could actually add those any typings anyway if we dont find corresponding types in the typings?
Sorry, I forgot to reply to this thread.
To add some backgrounds:
@types/ioredis was created before the migration.redis.get) are generated in runtime, thus the method definitions won't be included in the declaration. This is the reason why @types/ioredis is still required.As for the solution, either keeping using @types/ioredis or exposing declarations directly in ioredis repo works for me. For now, I'd think long-term we should expose declarations directly both for better developer experience and making declarations easier to maintain.
It's worth noticing that different Redis versions can have different command declarations. For example, old Redis versions only support AUTH password but in 6.x the command supports two parameters: AUTH username password. Having said that, I think the difference is minor and we can just align the declarations with the latest Redis version (or even better, we can include the version difference in the method descriptions).
redis-doc is unfortunately not in a machine readable style.
I think Redis website is generated from https://github.com/antirez/redis-doc/blob/master/commands.json, which do provide some typing infos like "SET":
"SET": {
"summary": "Set the string value of a key",
"complexity": "O(1)",
"arguments": [
{
"name": "key",
"type": "key"
},
{
"name": "value",
"type": "string"
},
{
"name": "expiration",
"type": "enum",
"enum": [
"EX seconds",
"PX milliseconds"
],
"optional": true
},
{
"name": "condition",
"type": "enum",
"enum": [
"NX",
"XX"
],
"optional": true
},
{
"name": "keepttl",
"type": "enum",
"enum": [
"KEEPTTL"
],
"optional": true
}
],
"since": "1.0.0",
"group": "string"
},
There are integers, strings, and even enums. However, I can see there are some challenges in mapping them to TypeScript declarations.
Anyway, PRs are welcome for adding more types!
@luin
I would still recommend to have a "complete" list of operation set. So I wanted to work now on an extended typing generation. It would be like this:
create any typed methods like described above and use declaration merging of typescript so we can add another namespace like Pipeline and thus resulting, that we have next to the current typings also any typings.
"attach" the new namespaces to the current index.d.ts file.
Now you have all methods of redis.
Oha!
I think I can make from that commands.js proper typings!
Btw, the @types/ioredis seems to have the xread and xreadgroup typing wrong. See https://github.com/DefinitelyTyped/DefinitelyTyped/issues/44301
Also, other types are relatively hard to work with. For example, xadd does not support simple variadic, and it made our code impossible to type. I had to add xadd(key: string, ...args: ValueType[]): Promise<string>.
And to make things even more complicated, now, overriding the IORedis.Redis type is not possible since the last few versions, so, you you have to something like.
export interface IORedisFixedType extends Omit<IORedis.Redis, 'xread' | 'xreadgroup' | 'xgroup' | 'xadd' | 'pipeline'> {
xread: (...args: ValueType[]) => Promise<StreamReadRaw | null>;
xreadgroup(...args: ValueType[]): Promise<StreamReadRaw>;
xgroup(...args: ValueType[]): Promise<Ok | number>;
xadd(key: string, ...args: ValueType[]): Promise<string>
pipeline(): PipelineFixedType
}
Anyway, all of these changes work great in our redstream redis stream library but it would be nice not just uses the ioredis correct types.
Wrote a little PoC
https://github.com/Uzlopak/ioredis-types
the generated.d.ts still contains some errors but is there anybody interested on collaborate on the generation of the right typings?
I think following steps have to be done to have a productive state:
ACL AUTHnice to have
const redis = new Redis<"6.0.0">() @jeremychone
Btw, the @types/ioredis seems to have the xread and xreadgroup typing wrong. See DefinitelyTyped/DefinitelyTyped#44301
Also, other types are relatively hard to work with. For example,
xadddoes not support simple variadic, and it made our code impossible to type. I had to addxadd(key: string, ...args: ValueType[]): Promise<string>.And to make things even more complicated, now, overriding the IORedis.Redis type is not possible since the last few versions, so, you you have to something like.
export interface IORedisFixedType extends Omit<IORedis.Redis, 'xread' | 'xreadgroup' | 'xgroup' | 'xadd' | 'pipeline'> { xread: (...args: ValueType[]) => Promise<StreamReadRaw | null>; xreadgroup(...args: ValueType[]): Promise<StreamReadRaw>; xgroup(...args: ValueType[]): Promise<Ok | number>; xadd(key: string, ...args: ValueType[]): Promise<string> pipeline(): PipelineFixedType }Anyway, all of these changes work great in our redstream redis stream library but it would be nice not just uses the ioredis correct types.
Not only that, but 'hset' is not variadic as well.
I've just started using ioredis and already got typing problems.
There should be a meme somewhere with "TypeScript Type Definitions: Expectation | Reality" :smile:.
Besides jokes, ioredis is the only package that supports Redis Sentinels (if memory doesn't fail), and having proper typing is very critical.
@Uzlopak
use generic type for Redis to inject the right version of used redis server so that you have on compile time the right set of commands, e.g. const redis = new Redis<"6.0.0">()
Is Redis using proper semantic versioning?
If they do, all commands should be backward-compatible right?
So we can actually pre-define major Redis versions and use them as
import { v6 as Redis } from 'ioredis'
const redis = new Redis(/*...*/)
/*...*/
@luin thanks for the context.
IMO, while code-gen the types could be good to get started, it will eventually need to hand-tuned and maintained for better developer experience.
One example of fine-tuning would be xread can return null, whereas xreadgroup cannot. We can try to express that in another definition file, but at some point there are diminishing return, moreover of APIs that relatively static anyway.
An alternative would be to use the type of the source code, and for the methods that are code gen, generate the TypeScript version of the code. This might not help the nuance above, but at least, it will keep types closer to implementation, which always help accuracy in Typescript.
Those are just some thoughts. Unfortunately, I swamped these days, and we are mostly using stream API, which I have already wrapped. If/when we use more of redis API, we might contribute in some ways.
Most helpful comment
I am confused. I must be missing something.
.ts@types/iorediswhich I did.@types/ioredisseems to be relatively off, as for example.xread(...args: ValueType[]): Array<[string, string[]]>;, which should unionnullas result, and even the type seems to be incomplete. For now, I do (which is not optimimum)So,
a) I am not sure if
@types/ioredisis generated from this project .ts, but right now it seems really off.b) I do not know how many more apis defined in
@types/ioredisare not aligned withioredisc) I read the #981 #issuecomment-538718567, but even having a "any" for some of those corner cases before generic can be figured out would be nice. Right now, I am not even sure how the types can be used (at last for
xread)We plan to move to
ioredisfromnode-redismostly because of the native promise/async/await support, but those typing issues are making us a little worried.