'Typescript factory of generic interface in

I'm creating a factory like this:

interface IOperator<T> {
  parse(arg: string): T;
  doSomething(value: T): void;
}

2 operators:

class StringOperator implements IOperator<string> {
  parse(arg: string) {
    return arg;
  }
  doSomething(value: string) { /* some logic */}
}

class NumberOperator implements IOperator<number> {
  parse(arg: string) {
    return parseInt(arg, 10);
  }
  doSomething(value: number) { /* some logic */}
}

the factory:

const operatorMap = {
  STRING: StringOperator,
  NUMBER: NumberOperator,
};

export const supportedOperators = Object.keys(operatorMap);

type OperatorMap = typeof operatorMap;
export type Operators = keyof OperatorMap;

type Tuples<T> = T extends Operators
  ? [T, InstanceType<OperatorMap[T]>]
  : never;
type SingleOperators<K> = [K] extends (K extends Operators ? [K] : never)
  ? K
  : never;
type ClassType<A extends Operators> = Extract<Tuples<Operators>, [A, any]>[1];

export class OperatorFactory {
  static create<K extends Operators>(k: SingleOperators<K>): ClassType<K> {
    return new operatorMap[k]();
  }
}

and use them like this:

const operator = OperatorFactory.create(operatorName);
const theValue = operator.parse(theArgument);
return operator.doSomething(theValue);

I get the message:

const theValue: string | number
Argument of type 'string | number' is not assignable to parameter of type 'never'.
  Type 'string' is not assignable to type 'never'.ts(2345)

Please check Playground Link for details.

I assume the issue is theValue can be string | number but .doSomething() only accept one value type.

If I let .doSomething(theValue: unknown) then do the conversion inside doSomething it will work, but it's not what I expected.

What should I do to make this pattern work in good practice pattern?

Thanks,



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source