Home > Back-end >  Dynamically define argument type
Dynamically define argument type

Time:05-13

I'm writing a library with TypeScript. It's meant to be a super-set of a configuration language, and itself configurable.

In a particular context, I want to declare a class with an object of essentially any shape, which will be converted to the expected shape by a function which the user of the library can provide (and for which I provide a default). The super-simplified version:

// Defined by a library user
interface Input {
  myName: string;
};

// Defined by my library, and non-configurable
interface Output {
  name: string;
};

// Defined by a library user (with a default fallback)
const mappingFunc = (input: Input): Output => ({
  name: input.myName
});

new MyClass({ myName: "Whatever" }, mappingFunc);

Within the class, the mappingFunc will generate the object the class manipulates (and a default mapping func will just accept and return an output-shaped object), but this pattern allows users of the lib to specify a mapping they want, and declare the object shape they want passed in, so long as the mapping function returns an output-shaped object.

Any idea how to do this, or if it's possible? I tried the below, but no dice. The type checker did not detect that the input didn't match the input interface, and in fact didn't check the input at all.

// Defined by my library
interface Output {
  name: string;
};

// Defined by my library
const makeClass = (mappingFunc: (unknown) => Output) =>
  class SpecifiedMyClass(input: unknown) {
     // Uses mappingFunc internally
  }
  return SpecifiedMyClass
}

// Below defined by user of the library
interface Input {
  myName: string;
};

const typedMappingFunc = (input: Input): Output => ({
  name: input.myName
});

const MyClass = makeClass(typedMappingFunc);

new MyClass({ myName: "Whatever" });

What'd I'm trying to do is to able to declare the type of the input arg into the MyClass be defined dynamically. Any ideas? Hard to explain.

CodePudding user response:

// Defined by my library
const makeClass = <T extends unknown>(mappingFunc: (T) => Output) =>
  class SpecifiedMyClass(input: T) {
     // Uses mappingFunc internally
  }
  return SpecifiedMyClass
}

Maybe I didn't understand the problem correctly, however I think this should solve your problem.

  • Related