根据作为参数传递的JSON模式键入函数

I have a factory function createF that takes as input a JSON schema and outputs a function f that returns object that fits this schema, it looks like:

const createF = (schema) => { /* ... */ }

const f1 = createF({
  type: 'integer',
});
type T1 = number;

const f2 = createF({
  type: 'object',
  required: ['a'],
  properties: {
    a: { type: 'number' },
    b: { type: 'string' },
  },
});
type T2 = {
  a: number;
  b?: string;
  [key: string]: any;
};

f1 and f2 always return objects that are shaped like T1 and T2 respectively, but they are not typed: createF is not written so that TS infers the right types to f1 and f2. Would that be possible to rewrite createF so that it does? If yes, how?

I know that it is possible to have a return type that depends on parameters by using function overloading, but in my case all the possible inputs are all JSON schemas and I don't know how to extend the function overloading solution to this case.

Currently, I use json-schema-to-typescript to generate at compile time types around the functions created by createF, but this is not ideal.

A bit of context to avoid the XY problem: I am actually building oa-client, a lib that creates a helper based on OpenAPI specs, which contains schemas. At runtime, the created helper only accepts and returns objects defined in the schemas; but on the TS layer there is no types - I have to use the schemas to write TS using node scripts, and that is not ideal, especially since the goal of oa-client is to not do code generation.

评论
et_et
et_et

This seems like a trivial problem for generics. I'm not exactly sure what your createF function body will look like, but you can see with the use of the generic <T> that the type of the schema argument can be preserved and used to determine the type of the returned function. You don't even need to change the way you're calling createF(), just the function declaration itself, and not even very much:

function createF<T> (schema: T) {
    return () => schema;
}

const f1 = createF({
  type: 'integer',
});
type T1 = number;

const f2 = createF({
  type: 'object',
  required: ['a'],
  properties: {
    a: { type: 'number' },
    b: { type: 'string' },
  },
});
type T2 = {
  a: number;
  b?: string;
  [key: string]: any;
};

TypeScript will now infer what the type of the returned function is based on the argument you passed to createF():

enter image description here

泛型就像声明您的类型具有参数一样,类似于传统函数。像函数一样,“参数”(或“泛型”)在声明该类型的值之前没有值(或类型)。

点赞
评论