0

Say I have this generic interface:

interface IProcessor<T>{
  process(param:T):T;
}

And it's implemented like this:

interface User{
  name:string;
}

class WebProcessorImplementation implements IProcessor<User>{
  process(param: User): User {
    console.log(`process user`);
    return {
      name:"User"
    }
  }
}

If I want to use an array of that generic interface, I get the complaint:

class Coordinator {
  processors:IProcessor[] //Generic type 'IProcessor<T>' requires 1 type argument(s).ts(2314)
}

Is there a way to tell Typescript everything will be ok here and that we will be passing it full implementations of this interface and the type parameter is not needed? I'm open to other approaches to solve my use case.

3
  • 2
    TypeScript doesn't have direct support for existential types (see microsoft/TypeScript#14466), which is what you'd need to express what you're talking about. But the example doesn't seem to have a motivating use case; what could you possibly do with "an IProcessor<T> for some T I don't know"? For example, say you have a value c of type Coordinator... What can you pass to c.processors[0].process()? Commented May 11, 2020 at 19:25
  • 1
    Perhaps your IProcessor<T> interface needs to be fleshed out so that someone could do something with an instance of it without needing to know what T is. For example, { process(param:T):T; initialValue(): T} would at least mean that someone could call someProcessor.process(someProcessor.initialValue()) without knowing T. Commented May 11, 2020 at 19:27
  • 1
    @jcalz thanks for the response and input. You were right, the design here was flawed which should have been a red flag. I changed the interface so that process() doesn't return a generic, but a standard type defined in my app. Each interface implementation is now responsible for processing its own data and returning it in a common format. Commented May 13, 2020 at 13:11

2 Answers 2

1

Right now you set it up such that IProcessor requires a type argument, to make it optional give it a default type ie.

interface IProcessor<T = unknown>{ 
  process(param:T):T;
}

unknown would allow anything however, If the generic types need to match a certain pattern, you can enforce that pattern at least with an extends

interface User{
  name:string;
}

interface DetailedUser{
    name: string;
    id: number;
    admin: boolean;
}

interface IProcessor<T extends User = User>{
  process(param:T):T;
}

class Coordinator {
    processors: IProcessor[] = [] //fine
    processors1: IProcessor<{}>[] = [] //error
    processors2: IProcessor<{ name?: string}>[] = [] //error
    processors3: IProcessor<User>[] = [] // fine
    processors4: IProcessor<DetailedUser>[] = [] // also fine
}

tsplaygroud

Alernativly You can always just add the type directly without changing Iprocessor

class Coordinator {
  processors: IProcessor<User>[] = []; //assuming you want User..
}

tsPlayground

Sign up to request clarification or add additional context in comments.

Comments

0

To get it to compile, we could use any

class Coordinator {
  processors:IProcessor<any>[]
}

But that doesn't help if we're trying to access <T> inside Coordinator like @jcalz mentioned.

Ended up changing the interface definition to this:

type Result = {data:string}
interface IProcessor{
  process():Result;
}

Implementation

class WebProcessorImplementation implements IProcessor{
  process(): Result {
    console.log(`process something`);
    return {
      data:"User"
    }
  }
}

class Coordinator {
  processors:IProcessor[]
}

1 Comment

any is not type safe, so someone could write new Coordinator().processors.push({ process: (x: string) => 123 }) with no error. I'm not sure what your use case but I'd be very careful with using any here. As I said above, I don't know what the use case is since you can't really do anything with an IProcessor<T> without knowing T, so I don't know what the right answer here is.

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.