0

I have an interface called Converter

export interface Converter<T> {
  uuid: CUUID;
  decode: (value: Buffer) => Promise<T>;
  encode?: (value: T) => Promise<Buffer>;
}

And I am using an array of that in another file:

import{ Converter } from "./characteristic";

export type Converters = Converter<any>[];

export default class Service<C extends Converters> {
  private converters: C;

  constructor(converters: C = []) {
           // ^^^^^^^^^^^^^^^^^^ error
    this.converters = converters;
  }
}

I am getting an error when I want to assign an empty array as an initial value to that property:

Type 'never[]' is not assignable to type 'C'.
  'never[]' is assignable to the constraint of type 'C', but 'C' could be instantiated with a different subtype of constraint 'Converter<any>[]'.ts(2322)

I have tried changing my type to

export type Converters = Converter<any>[] | [];

without any luck

I can do this:

export default class Service<C extends Converters> {
  private converters: C | [] = [];
}

but I am not sure why I have to or if that even is an appropriate solution and not just a anti-pattern workaround. I don't even understand what the problem is here.

3
  • Right off the top of my head I cannot see why it doesn't work. But it might be helpful to know which version of TypeScript you are using? Commented Sep 5, 2019 at 15:32
  • Hey @fredrik I am using TypeScript 3.5.3 Commented Sep 5, 2019 at 15:37
  • It doesn't work because you can specify a more specific type such as [Converter<string>] (a one-tuple type) for C, and you can't assign the value [] to a one-tuple. Commented Sep 5, 2019 at 18:28

1 Answer 1

1

The following seems to work:

export interface Converter<T = any> {
  uuid: CUUID;
  decode: (value: Buffer) => Promise<T>;
  encode?: (value: T) => Promise<Buffer>;
}

export default class Service<C extends Converter> {
  private converters: C[];

  constructor(converters: C[] = []) {
    this.converters = converters;
  }
}

I think export type Converters = Converter<any>[]; must obscure that it is an array so it tries to compare never[] to Converters instead of [] (with possibility to .push(Converter)) to Converter[].

Edit: actually if the the Service is intended to only have Converters of a certain type not mixed (I don't know) it might be better to do:

export interface Converter<T> {
  uuid: CUUID;
  decode: (value: Buffer) => Promise<T>;
  encode?: (value: T) => Promise<Buffer>;
}

export default class Service<T> {
  private converters: Converter<T>[];

  constructor(converters: Converter<T>[] = []) {
    this.converters = converters;
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Hey William. Thank you, but this won't work for me. The Converters can have multiple types.
"This won't work for me" ... Wait, why doesn't the first solution given here with types like class Service<C extends Converter> { converters: C[]; constructor(converters: C[] = []) { ... }} work for you? C can be a union. If it really doesn't work I think we need a minimal reproducible example that shows why.
I'm sorry, I was assuming that the first the solution will work on an array of the same converter type, which I see now it is not. I kept working on my "thing" and have created another, more elaborate question where I am tacking the problem. I will close this question in favor of this one: stackoverflow.com/questions/57812051/… Sorry for the effort you have already put into this, but the other one is probably more precisely what I am trying to do

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.